Files
gottfriedleibniz 496ebf3d67 Ongoing effort to resolve GitHub Issue #806:
1. Acquire use of the signaling and response facility prior to system_reset
Hackaround to #806: "ARCHLVL cpu reset leading to interrupt handling race"

2. refactor: thread safe utility functions
Updates a few utility functions designated/considred MT-Safe by POSIX or most modern implementations (e.g., glibc).
2026-03-24 13:46:35 -07:00

311 lines
11 KiB
C

/* ARCHLVL.C (C) Copyright Jan Jaeger, 2010-2012 */
/* (C) Copyright "Fish" (David B. Trout), 2018-2019 */
/* Architecture Level functions */
/* */
/* Released under "The Q Public License Version 1" */
/* (http://www.hercules-390.org/herclic.html) as modifications to */
/* Hercules. */
#include "hstdinc.h"
#define _ARCHLVL_C_
#define _HENGINE_DLL_
#include "hercules.h"
#include "opcode.h" // Need DEF_INST
/*-------------------------------------------------------------------*/
/* (delineates ARCH_DEP from non-arch_dep) */
/*-------------------------------------------------------------------*/
#if !defined( _GEN_ARCH )
// _ARCH_NUM_0 has been built.
// Now build the other architectures...
#if defined( _ARCH_NUM_1 )
#define _GEN_ARCH _ARCH_NUM_1
#include "archlvl.c"
#endif
#if defined( _ARCH_NUM_2 )
#undef _GEN_ARCH
#define _GEN_ARCH _ARCH_NUM_2
#include "archlvl.c"
#endif
/*-------------------------------------------------------------------*/
/* (delineates ARCH_DEP from non-arch_dep) */
/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/
/* ACTUAL Architecture bit-masks */
/*-------------------------------------------------------------------*/
#undef NONE
#undef S370
#undef E390
#undef Z900
#undef Z390
#undef MALL
#define NONE 0x00 /* NO architectures or disabled */
#define S370 0x80 /* S/370 architecture */
#define E390 0x40 /* ESA/390 architecture */
#define Z900 0x20 /* z/Arch architecture */
#define Z390 (E390|Z900) /* BOTH ESA/390 and z/Arch */
#define MALL (S370|Z390) /* All architectures */
/*-------------------------------------------------------------------*/
/* Architecture Level Table */
/*-------------------------------------------------------------------*/
static ARCHTAB archtab[] =
{
//---------------------------------------------------------
//
// The "_ARCH_nnn_NAME" entries MUST come first. The
// 'get_archtab_by_arch' function expects it.
//
// The FIRST entry is our DEFAULT initial startup archi-
// tecture set by the 'init_default_archmode' function.
//
//---------------------------------------------------------
#if defined( _900 )
AT( _ARCH_900_NAME, ARCH_900_IDX, Z900 ) // "z/Arch" feat900.h
#endif
#if defined( _390 )
AT( _ARCH_390_NAME, ARCH_390_IDX, E390 ) // "ESA/390" feat390.h
#endif
#if defined( _370 )
AT( _ARCH_370_NAME, ARCH_370_IDX, S370 ) // "S/370" feat370.h
#endif
// Other supported names come afterwards, in any order.
#if defined( _370 )
AT( "S370", ARCH_370_IDX, S370 )
AT( "370", ARCH_370_IDX, S370 )
#endif
#if defined( _390 )
AT( "ESA390", ARCH_390_IDX, E390 )
AT( "E390", ARCH_390_IDX, E390 )
AT( "E/390", ARCH_390_IDX, E390 )
AT( "ESA", ARCH_390_IDX, E390 )
AT( "S/390", ARCH_390_IDX, E390 )
AT( "OS/390", ARCH_390_IDX, E390 )
AT( "S390", ARCH_390_IDX, E390 )
AT( "OS390", ARCH_390_IDX, E390 )
AT( "390", ARCH_390_IDX, E390 )
#endif
#if defined( _900 )
AT( "zArch", ARCH_900_IDX, Z900 )
AT( "z", ARCH_900_IDX, Z900 )
AT( "900", ARCH_900_IDX, Z900 )
AT( "Z900", ARCH_900_IDX, Z900 )
AT( "z/900", ARCH_900_IDX, Z900 )
AT( "ESAME", ARCH_900_IDX, Z900 )
AT( "ESA/ME", ARCH_900_IDX, Z900 )
#endif
};
/*-------------------------------------------------------------------*/
/* init_default_archmode (public) */
/*-------------------------------------------------------------------*/
void init_default_archmode()
{
// Called ONCE by bldcfg.c 'build_config' during system startup.
sysblk.arch_mode = archtab[0].num; // (always the first entry)
}
/*-------------------------------------------------------------------*/
/* get_archtab_by_arch */
/*-------------------------------------------------------------------*/
const ARCHTAB* get_archtab_by_arch( int archnum )
{
// An "Architecture mode" (archmode, arch_mode) is the same
// thing as an "Architecture number" (archnum, arch_num),
// which is simply an index value determined at build time
// depending on which architectures that Hercules was built
// with support for (ARCH_nnn_IDX #defined by featchk.h) and
// is used to index into architecture dependent tables such as
// the sysblk.facility_list and the opcode tables in opcode.c
size_t i;
for (i=0; i < _countof( archtab ); i++)
if (archtab[i].num == archnum)
return &archtab[i];
return NULL;
}
/*-------------------------------------------------------------------*/
/* get_archtab_by_name */
/*-------------------------------------------------------------------*/
const ARCHTAB* get_archtab_by_name( const char* name )
{
size_t i;
for (i=0; i < _countof( archtab ); i++)
if (strcasecmp( archtab[i].name, name ) == 0)
return &archtab[i];
return NULL;
}
/*-------------------------------------------------------------------*/
/* get_arch_name_by_arch */
/*-------------------------------------------------------------------*/
const char* get_arch_name_by_arch( int archnum )
{
const ARCHTAB* at = get_archtab_by_arch( archnum );
return at ? at->name : NULL;
}
/*-------------------------------------------------------------------*/
/* get_arch_name (public) */
/*-------------------------------------------------------------------*/
const char* get_arch_name( REGS* regs )
{
int archnum = regs ? regs->arch_mode : sysblk.arch_mode;
return get_arch_name_by_arch( archnum );
}
/*-------------------------------------------------------------------*/
/* get_archmode_by_name */
/*-------------------------------------------------------------------*/
static int get_archmode_by_name( const char* archname )
{
const ARCHTAB* at = get_archtab_by_name( archname );
return at ? at->num : -1;
}
/*-------------------------------------------------------------------*/
/* archlvl_cmd (public) */
/*-------------------------------------------------------------------*/
/* */
/* ARCHLVL S/370 | ESA/390 | z/ARCH */
/* */
/*-------------------------------------------------------------------*/
int archlvl_cmd( int argc, char* argv[], char* cmdline )
{
U64 old_mainsize = sysblk.mainsize;
U64 new_mainsize = sysblk.mainsize;
int old_arch_mode = sysblk.arch_mode;
int new_arch_mode = sysblk.arch_mode;
UNREFERENCED( cmdline );
UPPER_ARGV_0( argv );
/*-----------------------------------------------------*/
/* Display Architecture Mode? */
/*-----------------------------------------------------*/
if (argc < 2)
{
// "%-14s: %s"
WRMSG( HHC02203, "I", "ARCHLVL", get_arch_name( NULL ));
return 0;
}
/* Too many arguments? */
if (argc > 2)
{
// "Invalid command usage. Type 'help %s' for assistance."
WRMSG( HHC02299, "E", argv[0] );
return -1;
}
/*-----------------------------------------------------*/
/* Set Architecture */
/*-----------------------------------------------------*/
/* Make sure all CPUs are deconfigured or stopped */
if (!are_all_cpus_stopped())
{
// "All CPU's must be stopped %s"
WRMSG( HHC02253, "E", "to switch architectures" );
return HERRCPUONL;
}
/* Determine new architecture mode */
if ((new_arch_mode = get_archmode_by_name( argv[1] )) < 0)
{
// "ARCHLVL '%s' is invalid"
WRMSG( HHC00895, "E", argv[1] );
return -1;
}
obtain_lock( &sysblk.sigplock );
{
OBTAIN_INTLOCK( NULL );
/* Nothing for us to do unless the architecture changed */
if (new_arch_mode != old_arch_mode )
{
/* Re-configure storage if MAINSIZE needs to be adjusted */
if ((new_mainsize = adjust_mainsize( new_arch_mode, sysblk.mainsize )) != old_mainsize)
configure_storage( new_mainsize >> SHIFT_4K );
/* Perform system reset to switch architecture mode */
{
static const bool clear = false, ipl = false;
system_reset( new_arch_mode, clear, ipl, sysblk.pcpu );
}
/* (ensure dummyregs matches new architecture) */
sysblk.dummyregs.arch_mode = sysblk.arch_mode;
}
/* ALWAYS do an "initial_cpu_reset()" for all processors */
initial_cpu_reset_all();
RELEASE_INTLOCK( NULL );
}
release_lock( &sysblk.sigplock );
/* Display results */
if (argc > 1 && MLVL( VERBOSE ))
{
// "%-14s set to %s"
WRMSG( HHC02204, "I", "ARCHLVL", get_arch_name_by_arch( sysblk.arch_mode ));
if (new_mainsize != old_mainsize)
{
char memsize[64];
bool increased = (new_mainsize > old_mainsize);
fmt_memsize_KB( sysblk.mainsize >> SHIFT_KIBIBYTE, memsize, sizeof( memsize ));
// "MAINSIZE %screased to %s architectural %simum"
WRMSG( HHC17006, "W", increased ? "in" : "de", memsize,
increased ? "min" : "max" );
}
}
/* If S/370 archmode was just set, force LPARNUM to BASIC.
Else if LPARNUM is BASIC, change it back to LPARNUM 1
if archmode is z/Arch. Else (ARCH_390_IDX) leave it alone.
The user can override this automatic LPARNUM switching
via their own subsequent LPARNUM stmt/cmd if such auto-
matic behavior is not desired.
*/
if (1
&& ARCH_370_IDX == sysblk.arch_mode
&& om_basic != sysblk.operation_mode
)
panel_command( "LPARNUM BASIC" );
else if (1
&& ARCH_900_IDX == sysblk.arch_mode
&& om_basic == sysblk.operation_mode
)
{
panel_command( "LPARNUM 1" );
panel_command( "CPUIDFMT 0" );
}
return 0;
}
#endif /* !defined( _GEN_ARCH ) */