mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-09 22:01:57 +02:00
7981 lines
290 KiB
C
7981 lines
290 KiB
C
/* CONTROL.C (C) Copyright Roger Bowler, 1994-2012 */
|
|
/* (C) Copyright Jan Jaeger, 1999-2012 */
|
|
/* (C) and others 2013-2024 */
|
|
/* ESA/390 CPU Emulator */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
/* Interpretive Execution - (C) Copyright Jan Jaeger, 1999-2012 */
|
|
/* z/Architecture support - (C) Copyright Jan Jaeger, 1999-2012 */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 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*/
|
|
/* PER 1 GRA - Fish Jan 2022*/
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#include "hstdinc.h"
|
|
|
|
#define _CONTROL_C_
|
|
#define _HENGINE_DLL_
|
|
|
|
#include "hercules.h"
|
|
#include "opcode.h"
|
|
#include "inline.h"
|
|
#include "sie.h"
|
|
|
|
|
|
#if defined( FEATURE_SUBSPACE_GROUP )
|
|
/*-------------------------------------------------------------------*/
|
|
/* 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 + 0 );
|
|
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 + 0 );
|
|
ssaste[2] = fetch_fw( p + 8 );
|
|
#if defined(FEATURE_001_ZARCH_INSTALLED_FACILITY)
|
|
ssaste[3] = fetch_fw( p + 12 );
|
|
#endif
|
|
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 */
|
|
#endif /* FEATURE_SUBSPACE_GROUP */
|
|
|
|
/* When an operation code has unused operand(s) (IPK, e.g.), it will */
|
|
/* attract a diagnostic for a set, but unused variable. Fixing the */
|
|
/* macros to support e.g., RS_NOOPS is not productive, so: */
|
|
DISABLE_GCC_UNUSED_SET_WARNING
|
|
|
|
/* 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 */
|
|
#if defined( FEATURE_TRACING )
|
|
CREG newcr12 = 0; /* CR12 upon completion */
|
|
#endif
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
/* 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_STATE_BIT_ON( regs, IC1, BSA ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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 ))
|
|
{
|
|
#if defined( FEATURE_SUPPRESSION_ON_PROTECTION )
|
|
regs->TEA = (ducto & STORAGE_KEY_PAGEMASK);
|
|
regs->excarid = 0;
|
|
#endif
|
|
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_001_ZARCH_INSTALLED_FACILITY )
|
|
/* 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
|
|
/* 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
|
|
|
|
/* 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 );
|
|
|
|
#if defined( 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
|
|
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
{
|
|
duct_reta = PSW_IA_FROM_IP( regs, 0 );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
duct_reta = PSW_IA_FROM_IP( 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_001_ZARCH_INSTALLED_FACILITY )
|
|
/* 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
|
|
/* 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
|
|
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
{
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, regs->GR_G( r2 ) );
|
|
}
|
|
else
|
|
#endif
|
|
if (regs->GR_L( r2 ) & 0x80000000)
|
|
{
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
regs->psw.amode64 = 0;
|
|
#endif
|
|
regs->psw.amode = 1;
|
|
regs->psw.AMASK = AMASK31;
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, regs->GR_L( r2 ) );
|
|
}
|
|
else
|
|
{
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
regs->psw.amode64 =
|
|
#endif
|
|
regs->psw.amode = 0;
|
|
regs->psw.AMASK = AMASK24;
|
|
SET_PSW_IA_AND_MAYBE_IP( 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 );
|
|
|
|
#if defined( 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
|
|
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
{
|
|
regs->GR_G( r1 ) = PSW_IA_FROM_IP( regs, 0 );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
regs->GR_L( r1 ) = PSW_IA_FROM_IP( regs, 0 );
|
|
if (regs->psw.amode) regs->GR_L( r1 ) |= 0x80000000;
|
|
}
|
|
}
|
|
|
|
/* Restore PSW amode and instruction address from the DUCT */
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
{
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, duct_reta );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
regs->psw.amode = (duct_reta & DUCT_AM31) ? 1 : 0;
|
|
regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24;
|
|
SET_PSW_IA_AND_MAYBE_IP( 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_001_ZARCH_INSTALLED_FACILITY )
|
|
ARCH_DEP( store_fullword_absolute )( duct_pkrp, ducto+20, regs );
|
|
#else
|
|
ARCH_DEP( store_fullword_absolute )( duct_pkrp, ducto+36, regs );
|
|
#endif
|
|
|
|
/* Specification exception if the PSW is now invalid...
|
|
|
|
Since the SET_PSW_IA_AND_MAYBE_IP macro used above
|
|
masks off invalid bits in the psw.IA, the only way to
|
|
know if the PSW is now invalid is to test the duct_reta
|
|
itself for any invalid bits.
|
|
*/
|
|
if (0
|
|
|| (duct_reta & 1)
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
|| (1
|
|
&& !regs->psw.amode64
|
|
&& !regs->psw.amode
|
|
&& (duct_reta & 0x7F000000)
|
|
)
|
|
#else
|
|
|| (1
|
|
&& !regs->psw.amode
|
|
&& duct_reta > 0x00FFFFFF
|
|
)
|
|
#endif
|
|
)
|
|
{
|
|
/* The program_interrupt routine invokes INVALIDATE_AIA
|
|
which applies the addressing mask to the psw.IA when
|
|
the aie is still valid, which we don't want it to do.
|
|
Thus we deliberately set the aie to an invalid value
|
|
to prevent it from doing that.
|
|
*/
|
|
regs->aie = INVALID_AIE;
|
|
regs->psw.IA = duct_reta;
|
|
regs->psw.zeroilc = 1;
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
}
|
|
|
|
} /* end if (BSA-ra) */
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
/* Update trace table address if branch tracing is on */
|
|
if (regs->CR( 12 ) & CR12_BRTRACE)
|
|
regs->CR( 12 ) = newcr12;
|
|
#endif
|
|
|
|
/* 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 */
|
|
#if defined( FEATURE_TRACING )
|
|
CREG newcr12 = 0; /* CR12 upon completion */
|
|
#endif
|
|
CREG inst_cr; /* Instruction CR */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
SIE_XC_INTERCEPT( regs );
|
|
|
|
/* Special operation exception if DAT is off or ASF not enabled */
|
|
if (REAL_MODE( ®s->psw )
|
|
|| !ASF_ENABLED( regs ))
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIAL_OPERATION_EXCEPTION );
|
|
|
|
inst_cr = regs->CR( regs->AEA_AR( USE_INST_SPACE ));
|
|
|
|
#if defined( 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
|
|
|
|
/* 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 ))
|
|
{
|
|
#if defined( FEATURE_SUPPRESSION_ON_PROTECTION )
|
|
regs->TEA = (ducto & STORAGE_KEY_PAGEMASK);
|
|
regs->excarid = 0;
|
|
#endif
|
|
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 + 0 );
|
|
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 + 0 );
|
|
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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
regs->GR_G( r1 ) = PSW_IA_FROM_IP( regs, 0 );
|
|
else
|
|
#endif
|
|
regs->GR_L( r1 ) = PSW_IA_FROM_IP( regs, 0 ) |
|
|
(regs->psw.amode ? 0x80000000 : 0);
|
|
}
|
|
|
|
/* Update the breaking event address register */
|
|
SET_BEAR_REG( regs, regs->ip - 4 );
|
|
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64 == 0 && (newia & 0x80000000))
|
|
#else
|
|
if (newia & 0x80000000)
|
|
#endif
|
|
{
|
|
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 */
|
|
SET_PSW_IA_AND_MAYBE_IP( 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 );
|
|
}
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
#if defined( 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
|
|
|
|
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 */
|
|
#if defined( FEATURE_TRACING )
|
|
VADR n = 0; /* Work area */
|
|
#endif
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
SIE_XC_INTERCEPT( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC3, BAKR ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* [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_001_ZARCH_INSTALLED_FACILITY )
|
|
if ((n1 & 0x01) == 0)
|
|
n1 &= (n1 & 0x80000000) ? 0xFFFFFFFF : 0x00FFFFFF;
|
|
#else
|
|
if ((n1 & 0x80000000) == 0)
|
|
n1 &= 0x00FFFFFF;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
n1 = PSW_IA_FROM_IP( regs, 0 );
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
n1 |= 0x01;
|
|
else
|
|
#endif
|
|
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_FROM_IP( regs, 0 );
|
|
n2 &= ADDRESS_MAXWRAP( regs );
|
|
|
|
/* Set the addressing mode bit in the branch address */
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
n2 |= 0x01;
|
|
else
|
|
#endif /* defined( FEATURE_001_ZARCH_INSTALLED_FACILITY ) */
|
|
if (regs->psw.amode)
|
|
n2 |= 0x80000000;
|
|
|
|
#if defined( 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
|
|
|
|
/* Form the linkage stack entry */
|
|
ARCH_DEP( form_stack_entry )( LSED_UET_BAKR, n1, n2, 0, 0, regs );
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
/* Update CR12 to reflect the new branch trace entry */
|
|
if ((regs->CR( 12 ) & CR12_BRTRACE) && (r2 != 0))
|
|
regs->CR( 12 ) = n;
|
|
#endif
|
|
|
|
/* Execute the branch as long as R2 is non-zero */
|
|
if (r2)
|
|
{
|
|
SET_BEAR_REG( regs, regs->ip - 4 );
|
|
SET_PSW_IA_AND_MAYBE_IP( 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 ) \
|
|
|| defined( FEATURE_003_DAT_ENHANCE_FACILITY_1 )
|
|
/*-------------------------------------------------------------------*/
|
|
/* Common processing function for CSP/CSPG instructions */
|
|
/*-------------------------------------------------------------------*/
|
|
void ARCH_DEP( compare_and_swap_and_purge_instruction )( BYTE inst[], REGS* regs, bool CSPG )
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
U64 n2; /* Virtual address of op2 */
|
|
BYTE* main2; /* Mainstor address of op2 */
|
|
|
|
U32 old32; /* Old value (CSP) */
|
|
U32 new32; /* New value (CSP) */
|
|
|
|
U64 old64; /* Old value (CSPG) */
|
|
U64 new64; /* New value (CSPG) */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
TXF_MISC_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
ODD_CHECK( r1, regs );
|
|
|
|
PER_ZEROADDR_CHECK( regs, r2 );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC0, IPTECSP ))
|
|
SIE_INTERCEPT( regs );
|
|
#endif
|
|
|
|
PERFORM_SERIALIZATION( regs );
|
|
{
|
|
OBTAIN_INTLOCK( regs );
|
|
{
|
|
SYNCHRONIZE_CPUS( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_MODE( regs ) && regs->sie_scao)
|
|
{
|
|
/* Try to obtain the SCA IPTE interlock. If successfully
|
|
obtained, then continue normally. Otherwise ask z/VM
|
|
to please intercept & execute this instruction itself.
|
|
*/
|
|
if (!TRY_OBTAIN_SCALOCK( regs ))
|
|
{
|
|
RELEASE_INTLOCK( regs );
|
|
SIE_INTERCEPT( regs );
|
|
}
|
|
}
|
|
#endif
|
|
/* Obtain 2nd operand address from r2 */
|
|
if (CSPG)
|
|
{
|
|
n2 = regs->GR( r2 ) & 0xFFFFFFFFFFFFFFF8ULL & ADDRESS_MAXWRAP( regs );
|
|
main2 = MADDRL( n2, 8, r2, regs, ACCTYPE_WRITE, regs->psw.pkey );
|
|
|
|
old64 = CSWAP64( regs->GR_G( r1 ));
|
|
new64 = CSWAP64( regs->GR_G( r1+1 ));
|
|
}
|
|
else
|
|
{
|
|
n2 = regs->GR( r2 ) & 0xFFFFFFFFFFFFFFFCULL & ADDRESS_MAXWRAP( regs );
|
|
main2 = MADDRL( n2, 4, r2, regs, ACCTYPE_WRITE, regs->psw.pkey );
|
|
|
|
old32 = CSWAP32( regs->GR_L( r1 ));
|
|
new32 = CSWAP32( regs->GR_L( r1+1 ));
|
|
}
|
|
|
|
/* MAINLOCK may be required if cmpxchg assists unavailable */
|
|
OBTAIN_MAINLOCK( regs );
|
|
{
|
|
/* Attempt to exchange the values */
|
|
if (CSPG)
|
|
regs->psw.cc = cmpxchg8( &old64, new64, main2 );
|
|
else
|
|
regs->psw.cc = cmpxchg4( &old32, new32, main2 );
|
|
}
|
|
RELEASE_MAINLOCK( regs );
|
|
|
|
if (regs->psw.cc == 0)
|
|
{
|
|
/* Perform requested function as per request-code in r2 */
|
|
if (regs->GR_L( r2 ) & 3)
|
|
{
|
|
/* Purge the TLB and/or ALB as requested */
|
|
#if defined( FEATURE_073_TRANSACT_EXEC_FACILITY )
|
|
if (FACILITY_ENABLED( 073_TRANSACT_EXEC, regs ))
|
|
txf_abort_all( regs->cpuad,
|
|
CSPG ? TXF_WHY_CSPG_INSTR
|
|
: TXF_WHY_CSP_INSTR, PTT_LOC );
|
|
#endif
|
|
if (regs->GR_L( r2 ) & 1)
|
|
ARCH_DEP( purge_tlb_all )( regs, 0xFFFF );
|
|
|
|
if (regs->GR_L( r2 ) & 2)
|
|
ARCH_DEP( purge_alb_all )( regs );
|
|
}
|
|
}
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
/* Release the SCA lock */
|
|
if (SIE_MODE( regs ) && regs->sie_scao)
|
|
RELEASE_SCALOCK( regs );
|
|
#endif
|
|
}
|
|
RELEASE_INTLOCK( regs );
|
|
}
|
|
PERFORM_SERIALIZATION( regs );
|
|
|
|
/* "Yield" if the swap failed, so as to give the
|
|
guest's retry a better chance of succeeding.
|
|
*/
|
|
if (regs->psw.cc != 0)
|
|
{
|
|
if (CSPG)
|
|
{
|
|
PTT_CSF( "*CSPG", regs->GR_G( r1 ), regs->GR_G( r2 ), regs->psw.IA_G );
|
|
regs->GR_G( r1 ) = CSWAP64( old64 );
|
|
}
|
|
else
|
|
{
|
|
PTT_CSF( "*CSP", regs->GR_L( r1 ) ,regs->GR_L( r2 ), regs->psw.IA_L );
|
|
regs->GR_L( r1 ) = CSWAP32( old32 );
|
|
}
|
|
|
|
if (sysblk.cpus > 1)
|
|
sched_yield();
|
|
}
|
|
|
|
} /* end compare_and_swap_and_purge_instruction */
|
|
#endif /* defined( FEATURE_BROADCASTED_PURGING )
|
|
|| defined( FEATURE_003_DAT_ENHANCE_FACILITY_1 ) */
|
|
|
|
|
|
#if defined( FEATURE_BROADCASTED_PURGING )
|
|
/*-------------------------------------------------------------------*/
|
|
/* B250 CSP - Compare and Swap and Purge [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( compare_and_swap_and_purge )
|
|
{
|
|
ARCH_DEP( compare_and_swap_and_purge_instruction )( inst, regs, false );
|
|
}
|
|
#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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
PTT_INF( "DIAG", regs->GR_G( r1 ), regs->GR_G( r3 ),
|
|
(U32)(effective_addr2 & 0xffffff) );
|
|
|
|
/* Let VM370 Assist take first crack at diagnose instructions */
|
|
#if defined( FEATURE_ECPSVM )
|
|
if (ecpsvm_dodiag( regs, r1, r3, b2, effective_addr2 ) == 0)
|
|
return;
|
|
#endif
|
|
/* Diagnose F08/F09 (Get Hercules Instruction Counter) is NOT
|
|
a privileged instruction and can be executed by ANY problem
|
|
state program as long as the HERC_PROBSTATE_DIAGF08 facility
|
|
is enabled. All OTHER diagnose instructions (including the
|
|
Diagnose F08 (Get Hercules Instruction Counter) instruction
|
|
when the HERC_PROBSTATE_DIAGF08 facility is NOT enabled)
|
|
ARE privileged and require supervisor state.
|
|
*/
|
|
#if defined( FEATURE_HERCULES_DIAGCALLS )
|
|
if (1
|
|
#if defined( _FEATURE_SIE )
|
|
&& !SIE_MODE( regs )
|
|
#endif
|
|
&& !(((effective_addr2 == 0xF08) ||
|
|
(effective_addr2 == 0xF09)) &&
|
|
FACILITY_ENABLED( HERC_PROBSTATE_DIAGF08, regs ))
|
|
)
|
|
#endif
|
|
{
|
|
/* Program Check Interrupt if not supervisor state */
|
|
PRIV_CHECK( regs );
|
|
}
|
|
|
|
/* Allow SIE to intercept this instruction */
|
|
SIE_INTERCEPT( regs );
|
|
|
|
/* Otherwise process this diagnose instruction */
|
|
regs->diagnose = TRUE;
|
|
{
|
|
ARCH_DEP( diagnose_call )( regs, r1, r3, b2, effective_addr2 );
|
|
}
|
|
regs->diagnose = FALSE;
|
|
|
|
/* Perform serialization and checkpoint-synchronization */
|
|
PERFORM_SERIALIZATION( regs );
|
|
PERFORM_CHKPT_SYNC( regs );
|
|
|
|
#if defined( 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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
|
|
} /* end DEF_INST(extract_primary_asn) */
|
|
#endif /* defined( FEATURE_DUAL_ADDRESS_SPACE ) */
|
|
|
|
|
|
#if defined( FEATURE_006_ASN_LX_REUSE_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* B99A EPAIR - Extract Primary ASN and Instance [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( extract_primary_asn_and_instance )
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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_006_ASN_LX_REUSE_FACILITY ) */
|
|
|
|
|
|
#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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
|
|
} /* end DEF_INST(extract_secondary_asn) */
|
|
#endif /* defined( FEATURE_DUAL_ADDRESS_SPACE ) */
|
|
|
|
|
|
#if defined( FEATURE_006_ASN_LX_REUSE_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* B99B ESAIR - Extract Secondary ASN and Instance [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( extract_secondary_asn_and_instance )
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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_006_ASN_LX_REUSE_FACILITY ) */
|
|
|
|
|
|
#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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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 );
|
|
|
|
#if defined( FEATURE_PER1 )
|
|
if (EN_IC_PER_GRA( regs ))
|
|
{
|
|
/* Check for PER 1 GRA event */
|
|
int i; U16 rmask = 0x0000;
|
|
if (r1 > r2)
|
|
{
|
|
for (i = r1; i <= 15; ++i)
|
|
rmask |= PER_GRA_MASK( i );
|
|
for (i = 0; i <= r2; ++i)
|
|
rmask |= PER_GRA_MASK( i );
|
|
}
|
|
else // (r1 <= r2)
|
|
for (i = r1; i <= r2; ++i)
|
|
rmask |= PER_GRA_MASK( i );
|
|
PER_GRA_CHECK( regs, rmask );
|
|
}
|
|
#endif
|
|
}
|
|
#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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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_006_ASN_LX_REUSE_FACILITY )
|
|
max_esta_code = FACILITY_ENABLED( 006_ASN_LX_REUSE, regs ) ? 5 : 4;
|
|
#elif defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
max_esta_code=4;
|
|
#else /*!defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )*/
|
|
max_esta_code=3;
|
|
#endif /*!defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )*/
|
|
|
|
/* 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;
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK2( r1, r1+1 ));
|
|
}
|
|
#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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
/* Special operation exception if DAT is off */
|
|
if (REAL_MODE( ®s->psw )
|
|
#if defined( FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE )
|
|
/* Except in XC mode */
|
|
&& !SIE_STATE_BIT_ON( regs, MX, XC )
|
|
#endif
|
|
)
|
|
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_STATE_BIT_ON( regs, MX, XC )
|
|
#endif
|
|
)
|
|
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;
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
}
|
|
#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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
/* 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;
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( 2 ));
|
|
}
|
|
|
|
|
|
#if defined( FEATURE_BASIC_STORAGE_KEYS )
|
|
/*-------------------------------------------------------------------*/
|
|
/* 09 ISK - Insert Storage Key [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( insert_storage_key )
|
|
{
|
|
int r1, r2; /* Operand register numbers */
|
|
RADR pageaddr; /* Working abs page address */
|
|
|
|
RR( inst, regs, r1, r2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
/* Special Operation Exception if Storkey exception control zero */
|
|
#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 */
|
|
pageaddr = regs->GR_L( r2 ) & 0x00FFF800;
|
|
|
|
/* Convert real address to absolute address */
|
|
pageaddr = APPLY_PREFIXING( pageaddr, regs->PX );
|
|
|
|
/* Addressing exception if block is outside of main storage */
|
|
if (pageaddr > regs->mainlim)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_ADDRESSING_EXCEPTION );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_MODE( regs ))
|
|
{
|
|
if (SIE_STATE_BIT_ON( regs, IC2, ISKE ))
|
|
SIE_INTERCEPT( regs );
|
|
|
|
if (!regs->sie_pref)
|
|
{
|
|
#if defined( _FEATURE_STORAGE_KEY_ASSIST )
|
|
if (1
|
|
&& SIE_STATE_BIT_ON( regs, RCPO0, ASIST )
|
|
&& SIE_STATE_BIT_ON( regs, RCPO2, RCPBY )
|
|
)
|
|
{
|
|
/* When "bypass use of RCP table" is requested
|
|
the guest page is assumed to be accessible.
|
|
*/
|
|
/* Translate guest absolute to host absolute */
|
|
SIE_TRANSLATE( &pageaddr, ACCTYPE_SIE, regs );
|
|
|
|
/* Insert the requested storage key */
|
|
regs->GR_LHLCL( r1 ) = ARCH_DEP( get_2K_storage_key )( pageaddr );
|
|
}
|
|
else // use RCP...(and possibly PGSTE)
|
|
#endif
|
|
{
|
|
PGSTE* pgste;
|
|
RCPTE* rcpte;
|
|
int sr;
|
|
BYTE oldkey;
|
|
|
|
ARCH_DEP( GetPGSTE_and_RCPTE )( regs, pageaddr, &pgste, &rcpte );
|
|
|
|
OBTAIN_KEYLOCK( pgste, rcpte, regs );
|
|
{
|
|
/* Translate guest absolute address to host real.
|
|
Note that the RCP table MUST be locked BEFORE
|
|
we try to access the real page!
|
|
*/
|
|
sr = SIE_TRANSLATE_ADDR( regs->sie_mso + pageaddr,
|
|
USE_PRIMARY_SPACE,
|
|
HOSTREGS, ACCTYPE_SIE );
|
|
if (sr == 0)
|
|
{
|
|
/* Translate host real to host absolute */
|
|
pageaddr = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
/* Save the original key */
|
|
oldkey = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
|
|
/* For ISK(E) include RCP table R/C bits too */
|
|
oldkey |= (rcpte->rcpbyte & RCPGUEST);
|
|
}
|
|
else // (sr != 0)
|
|
{
|
|
/* If the real page is inaccessible and SKA
|
|
is not active, then we cannot proceed since,
|
|
with the old non-SKA RCP table approach,
|
|
there isn't any other way to set or obtain
|
|
the page's access key and fetch-protect bits
|
|
since the old non-SKA RCP table contains
|
|
ONLY the R/C bits, but not anything else.
|
|
*/
|
|
if (!pgste)
|
|
{
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
SIE_INTERCEPT( regs );
|
|
}
|
|
|
|
/* Reconstruct the original storage key from
|
|
both the PGSTE and RCPTE entries.
|
|
*/
|
|
oldkey = (pgste->pgsvkey & PGSVKACF)
|
|
| (rcpte->rcpbyte & RCPGUEST);
|
|
}
|
|
|
|
/* Insert the requested storage key */
|
|
regs->GR_LHLCL( r1 ) = oldkey;
|
|
}
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
}
|
|
}
|
|
else /* sie_pref */
|
|
{
|
|
/* Insert the requested storage key */
|
|
regs->GR_LHLCL( r1 ) = ARCH_DEP( get_2K_storage_key )( pageaddr );
|
|
}
|
|
}
|
|
else /* !SIE_MODE */
|
|
#endif /* defined( _FEATURE_SIE ) */
|
|
{
|
|
/* Insert the storage key into r1 register bits 24-31 */
|
|
regs->GR_LHLCL( r1 ) = ARCH_DEP( get_2K_storage_key )( pageaddr );
|
|
}
|
|
|
|
/* 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 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
|
|
} /* end DEF_INST( insert_storage_key ) */
|
|
#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; /* Operand register numbers */
|
|
RADR pageaddr; /* Working abs page address */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
/* Load 4K block address from r2 register */
|
|
pageaddr = regs->GR( r2 ) & ADDRESS_MAXWRAP_E(regs);
|
|
|
|
/* Convert real address to absolute address */
|
|
pageaddr = APPLY_PREFIXING( pageaddr, regs->PX );
|
|
|
|
/* Addressing exception if block is outside of main storage */
|
|
if (pageaddr > regs->mainlim)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_ADDRESSING_EXCEPTION );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_MODE( regs ))
|
|
{
|
|
if (SIE_STATE_BIT_ON( regs, IC2, ISKE ))
|
|
SIE_INTERCEPT( regs );
|
|
|
|
if (!regs->sie_pref)
|
|
{
|
|
#if defined( _FEATURE_STORAGE_KEY_ASSIST )
|
|
if ((0
|
|
|| SIE_STATE_BIT_ON( regs, RCPO0, ASIST )
|
|
#if defined( _FEATURE_ZSIE )
|
|
// SKA is always active for z/VM
|
|
|| ARCH_900_IDX == HOSTREGS->arch_mode
|
|
#endif
|
|
)
|
|
&& SIE_STATE_BIT_ON( regs, RCPO2, RCPBY )
|
|
)
|
|
{
|
|
/* When "bypass use of RCP table" is requested
|
|
the guest page is assumed to be accessible.
|
|
*/
|
|
/* Translate guest absolute to host absolute */
|
|
SIE_TRANSLATE( &pageaddr, ACCTYPE_SIE, regs );
|
|
|
|
/* Insert the requested storage key */
|
|
regs->GR_LHLCL( r1 ) = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
}
|
|
else // use RCP...(and possibly PGSTE)
|
|
#endif /* defined( _FEATURE_STORAGE_KEY_ASSIST ) */
|
|
{
|
|
PGSTE* pgste;
|
|
RCPTE* rcpte;
|
|
int sr;
|
|
BYTE oldkey;
|
|
|
|
ARCH_DEP( GetPGSTE_and_RCPTE )( regs, pageaddr, &pgste, &rcpte );
|
|
|
|
OBTAIN_KEYLOCK( pgste, rcpte, regs );
|
|
{
|
|
/* Translate guest absolute address to host real.
|
|
Note that the RCP table MUST be locked BEFORE
|
|
we try to access the real page!
|
|
*/
|
|
sr = SIE_TRANSLATE_ADDR( regs->sie_mso + pageaddr,
|
|
USE_PRIMARY_SPACE,
|
|
HOSTREGS, ACCTYPE_SIE );
|
|
if (sr == 0)
|
|
{
|
|
/* Translate host real to host absolute */
|
|
pageaddr = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
/* Save the original key */
|
|
oldkey = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
|
|
/* For ISK(E) include RCP table R/C bits too */
|
|
oldkey |= (rcpte->rcpbyte & RCPGUEST);
|
|
}
|
|
else // (sr != 0)
|
|
{
|
|
/* If the real page is inaccessible and SKA
|
|
is not active, then we cannot proceed since,
|
|
with the old non-SKA RCP table approach,
|
|
there isn't any other way to set or obtain
|
|
the page's access key and fetch-protect bits
|
|
since the old non-SKA RCP table contains
|
|
ONLY the R/C bits, but not anything else.
|
|
*/
|
|
if (!pgste)
|
|
{
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
SIE_INTERCEPT( regs );
|
|
}
|
|
|
|
/* Reconstruct the original storage key from
|
|
both the PGSTE and RCPTE entries.
|
|
*/
|
|
oldkey = (pgste->pgsvkey & PGSVKACF)
|
|
| (rcpte->rcpbyte & RCPGUEST);
|
|
}
|
|
|
|
/* Insert the requested storage key */
|
|
regs->GR_LHLCL( r1 ) = oldkey;
|
|
}
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
}
|
|
}
|
|
else /* sie_pref */
|
|
{
|
|
/* Insert the requested storage key */
|
|
regs->GR_LHLCL( r1 ) = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
}
|
|
}
|
|
else /* !SIE_MODE */
|
|
#endif /* defined( _FEATURE_SIE ) */
|
|
{
|
|
/* Insert the storage key into r1 register bits 24-31 */
|
|
regs->GR_LHLCL( r1 ) = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
}
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
|
|
} /* 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; /* Operand-2 virtual page */
|
|
RADR pageaddr; /* Operand-2 page address */
|
|
BYTE vsk = 0; /* Virtual Storage Key */
|
|
bool need_realkey = true; /* (get from real page) */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( 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 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 */
|
|
pageaddr = APPLY_PREFIXING( regs->dat.raddr, regs->PX );
|
|
|
|
/* Addressing exception if block is outside main storage */
|
|
if (pageaddr > regs->mainlim)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_ADDRESSING_EXCEPTION );
|
|
|
|
#if defined( _FEATURE_STORAGE_KEY_ASSIST )
|
|
if (1
|
|
&& SIE_MODE( regs )
|
|
&& !regs->sie_pref
|
|
&& (0
|
|
|| SIE_STATE_BIT_ON( regs, RCPO0, ASIST )
|
|
#if defined( _FEATURE_ZSIE )
|
|
|| (HOSTREGS->arch_mode == ARCH_900_IDX)
|
|
#endif
|
|
)
|
|
&& !SIE_FEAT_BIT_ON( regs, RCPO2, RCPBY )
|
|
)
|
|
{
|
|
/* SIE_MODE and not sie_pref and SKA and not RCP bypass... */
|
|
int sr;
|
|
|
|
/* Convert guest abs to host abs (sr=0) or PTE abs (sr=2) */
|
|
sr = SIE_TRANSLATE_ADDR( regs->sie_mso + pageaddr,
|
|
USE_PRIMARY_SPACE,
|
|
HOSTREGS, ACCTYPE_SIE );
|
|
|
|
/* Translate host real to host absolute */
|
|
pageaddr = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
/* Program Check if any unexpected translation error */
|
|
if (sr != 0 && sr != 2)
|
|
{
|
|
switch (HOSTREGS->arch_mode)
|
|
{
|
|
case ARCH_370_IDX: s370_program_interrupt( HOSTREGS, HOSTREGS->dat.xcode ); break;
|
|
case ARCH_390_IDX: s390_program_interrupt( HOSTREGS, HOSTREGS->dat.xcode ); break;
|
|
case ARCH_900_IDX: z900_program_interrupt( HOSTREGS, HOSTREGS->dat.xcode ); break;
|
|
default: CRASH();
|
|
}
|
|
}
|
|
|
|
if (sr != 0)
|
|
{
|
|
/* sr == 2: host abs page corresponding to guest abs page
|
|
not available. pageaddr is thus host abs PTE instead.
|
|
Obtain needed key information from the PGSTE instead.
|
|
*/
|
|
PGSTE* pgste = ARCH_DEP( GetPGSTEFromPTE )( regs, pageaddr );
|
|
vsk = (pgste->pgsvkey & PGSVKACF);
|
|
need_realkey = false;
|
|
}
|
|
}
|
|
else /* Not SIE, or else sie_pref, or else RCP Bypass... */
|
|
#endif /* defined( _FEATURE_STORAGE_KEY_ASSIST ) */
|
|
{
|
|
/* When "bypass use of RCP table" is requested
|
|
the guest page is assumed to be accessible.
|
|
|
|
PROGRAMMING NOTE: if we're not in SIE mode,
|
|
then the below SIE_TRANSLATE statement does
|
|
absolutely nothing.
|
|
*/
|
|
/* Translate guest absolute to host absolute */
|
|
SIE_TRANSLATE( &pageaddr, ACCTYPE_SIE, regs );
|
|
}
|
|
|
|
/* Get needed key from the real page if it's available */
|
|
if (need_realkey)
|
|
vsk = ARCH_DEP( get_storage_key )( pageaddr )
|
|
& (STORKEY_KEY | STORKEY_FETCH);
|
|
|
|
/* Insert storage key bits 0-4 into r1 register bits
|
|
56-60 and set bits 61-63 to zeroes (i.e. get just
|
|
the access key and the fetch protect bit)
|
|
*/
|
|
regs->GR_LHLCL( r1 ) = vsk;
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
|
|
} /* end DEF_INST(insert_virtual_storage_key) */
|
|
#endif /* defined( FEATURE_DUAL_ADDRESS_SPACE ) */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B221 IPTE - Invalidate Page Table Entry [RRF-a] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( invalidate_page_table_entry )
|
|
{
|
|
int r1, r2; /* Operand register numbers */
|
|
#if defined( FEATURE_013_IPTE_RANGE_FACILITY ) || \
|
|
defined( FEATURE_051_LOCAL_TLB_CLEARING_FACILITY )
|
|
int r3; /* Operand-3 register number */
|
|
int m4; /* Operand-4 mask field */
|
|
#endif
|
|
RADR pto; /* Page Table Origin */
|
|
VADR vaddr; /* Virtual Address of first or
|
|
only page to invalidate */
|
|
int pageidx; /* Starting page index */
|
|
int pages = 1; /* Total Pages to invalidate */
|
|
int i; /* work (for loop iterator) */
|
|
bool local = false; /* true == m4 bit 3 is on */
|
|
#if defined( FEATURE_013_IPTE_RANGE_FACILITY )
|
|
bool do_range = false; /* helper flag */
|
|
#endif
|
|
|
|
#if defined( FEATURE_013_IPTE_RANGE_FACILITY ) || \
|
|
defined( FEATURE_051_LOCAL_TLB_CLEARING_FACILITY )
|
|
|
|
RRF_RM( inst, regs, r1, r2, r3, m4 );
|
|
|
|
#if defined( FEATURE_PER_ZERO_ADDRESS_DETECTION_FACILITY )
|
|
if ((regs->GR_G( r1 ) & 0xfffffffffffff000) == 0) // (bits 0-52)
|
|
ARCH_DEP( per3_zero )( regs );
|
|
#endif
|
|
|
|
if (1
|
|
&& (m4 & 0x01) /* LC == Local Clearing bit on? */
|
|
&& FACILITY_ENABLED( 051_LOCAL_TLB_CLEARING, regs )
|
|
)
|
|
local = true;
|
|
#else
|
|
RRE( inst, regs, r1, r2 );
|
|
#endif
|
|
|
|
TXF_MISC_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
pto = regs->GR( r1 );
|
|
vaddr = regs->GR( r2 );
|
|
pageidx = (vaddr >> SHIFT_4K) & 0xFF;
|
|
|
|
#if defined( FEATURE_013_IPTE_RANGE_FACILITY )
|
|
if (r3 && FACILITY_ENABLED( 013_IPTE_RANGE, regs ))
|
|
{
|
|
int additional_pages = regs->GR_LHLCL( r3 );
|
|
if ((pageidx + additional_pages) > 255)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
pages += additional_pages;
|
|
do_range = true;
|
|
}
|
|
#endif
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC0, IPTECSP ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* Perform serialization before operation */
|
|
PERFORM_SERIALIZATION( regs );
|
|
|
|
if (!local) OBTAIN_INTLOCK( regs );
|
|
{
|
|
if (!local) SYNCHRONIZE_CPUS( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
|
|
/* Try to obtain the SCA IPTE interlock. If successfully
|
|
obtained, then continue normally. Otherwise ask z/VM
|
|
to please intercept & execute this instruction itself.
|
|
*/
|
|
if (SIE_MODE( regs ) && regs->sie_scao)
|
|
{
|
|
if (!TRY_OBTAIN_SCALOCK( regs ))
|
|
{
|
|
if (!local) RELEASE_INTLOCK( regs );
|
|
SIE_INTERCEPT( regs );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined( FEATURE_073_TRANSACT_EXEC_FACILITY )
|
|
/* Abort any/all active transactions beforehand */
|
|
if (FACILITY_ENABLED( 073_TRANSACT_EXEC, regs ))
|
|
txf_abort_all( regs->cpuad, TXF_WHY_IPTE_INSTR, PTT_LOC );
|
|
#endif
|
|
/* Now invalidate all of the requested Page Table Entries */
|
|
for (i=0; i < pages; ++i, vaddr += _4K)
|
|
ARCH_DEP( invalidate_pte )( inst[1], pto, vaddr, regs, local );
|
|
|
|
#if defined( FEATURE_013_IPTE_RANGE_FACILITY )
|
|
/* Update registers if range was specified */
|
|
if (do_range)
|
|
{
|
|
regs->GR( r2 ) = vaddr;
|
|
regs->GR_LHLCL( r3 ) -= pages;
|
|
}
|
|
#endif
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
/* Release the SCA lock if we obtained it */
|
|
if (SIE_MODE( regs ) && regs->sie_scao)
|
|
RELEASE_SCALOCK (regs );
|
|
#endif
|
|
}
|
|
if (!local) 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 */
|
|
#if defined( FEATURE_SUBSPACE_GROUP )
|
|
U16 xcode; /* Exception code */
|
|
#endif
|
|
CREG inst_cr; /* Instruction CR */
|
|
|
|
SSE( inst, regs, b1, effective_addr1, b2, effective_addr2 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b1 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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_STATE_BIT_ON( regs, IC2, LASP ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
#if defined( 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
|
|
/* 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;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
#if defined( 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 /* defined( 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;
|
|
}
|
|
|
|
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-a] */
|
|
/*-------------------------------------------------------------------*/
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
#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
|
|
|
|
/* Calculate number of words to next boundary */
|
|
m = (PAGEFRAME_PAGESIZE - (effective_addr2 & PAGEFRAME_BYTEMASK)) >> 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 [SI] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( load_program_status_word )
|
|
{
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
DBLWRD dword;
|
|
int rc;
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
int amode64;
|
|
#endif
|
|
|
|
S( inst, regs, b2, effective_addr2 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
#if defined( FEATURE_ECPSVM )
|
|
if (ecpsvm_dolpsw( regs, b2, effective_addr2 ) == 0)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
DW_CHECK( effective_addr2, regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC1, LPSW ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
if ((rc = ARCH_DEP( load_psw )( regs, dword )))
|
|
ARCH_DEP( program_interrupt )( regs, rc );
|
|
#else
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY ) */
|
|
|
|
}
|
|
PERFORM_CHKPT_SYNC( regs );
|
|
PERFORM_SERIALIZATION( regs );
|
|
|
|
RETURN_INTCHECK( regs );
|
|
|
|
} /* end DEF_INST(load_program_status_word) */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B1 LRA - Load Real Address [RX-a] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( load_real_address )
|
|
{
|
|
int r1; /* Register number */
|
|
int x2; /* Index register */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
RX( inst, regs, r1, x2, b2, effective_addr2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
#if defined( FEATURE_ECPSVM )
|
|
if (ecpsvm_dolra( regs, r1, b2, effective_addr2 ) == 0)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
ARCH_DEP( load_real_address_proc )( regs, r1, b2, effective_addr2 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
|
|
} /* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
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
|
|
regs->GR_L( r1 ) = regs->dat.raddr;
|
|
#endif /*!defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )*/
|
|
} /* 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 );
|
|
|
|
PER_ZEROADDR_CHECK( regs, r2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
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 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
}
|
|
|
|
|
|
#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 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
if (REAL_MODE( ®s->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_UNCONDITIONAL( 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_001_ZARCH_INSTALLED_FACILITY )
|
|
ARCH_DEP( fetch_doubleword_absolute )( rpte, regs );
|
|
#else
|
|
ARCH_DEP( fetch_fullword_absolute )( rpte, regs );
|
|
#endif
|
|
|
|
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_UNCONDITIONAL( regs );
|
|
return;
|
|
}
|
|
|
|
pte |= PAGETAB_PGLOCK;
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
ARCH_DEP( store_doubleword_absolute )( pte, rpte, regs );
|
|
#else
|
|
ARCH_DEP( store_fullword_absolute )( pte, rpte, regs );
|
|
#endif
|
|
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_001_ZARCH_INSTALLED_FACILITY )
|
|
ARCH_DEP( store_doubleword_absolute )( pte, rpte, regs );
|
|
#else
|
|
ARCH_DEP( store_fullword_absolute )( pte, rpte, regs );
|
|
#endif
|
|
regs->psw.cc = 0;
|
|
}
|
|
else
|
|
regs->psw.cc = 1;
|
|
}
|
|
|
|
}
|
|
else
|
|
regs->psw.cc = 3;
|
|
|
|
RELEASE_MAINLOCK_UNCONDITIONAL( 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, r2; /* 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, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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 + 0 );
|
|
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-d] */
|
|
/*-------------------------------------------------------------------*/
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK2( regs, b1, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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-d] */
|
|
/*-------------------------------------------------------------------*/
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK2( regs, b1, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK2( regs, b1, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
/* 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-d] */
|
|
/*-------------------------------------------------------------------*/
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK2( regs, b1, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
/* 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_027_MVCOS_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* 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 );
|
|
|
|
PER_ZEROADDR_XCHECK2( regs, b1, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
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_027_MVCOS_FACILITY ) */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 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 );
|
|
|
|
PER_ZEROADDR_XCHECK2( regs, b1, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
/* 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
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
CREG newcr12 = 0; /* CR12 upon completion */
|
|
#endif
|
|
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
CREG savecr12 = 0; /* CR12 save */
|
|
#endif
|
|
|
|
S( inst, regs, b2, effective_addr2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
SIE_XC_INTERCEPT( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC2, PC ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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( ®s->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_001_ZARCH_INSTALLED_FACILITY )
|
|
aste[3] = ARCH_DEP( fetch_fullword_absolute )( abs+12, regs );
|
|
#else
|
|
aste[6] = ARCH_DEP( fetch_fullword_absolute )( abs+24, regs );
|
|
#endif
|
|
|
|
/* 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 );
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
/* Form trace entry if ASN tracing is active */
|
|
if (regs->CR( 12 ) & CR12_ASNTRACE)
|
|
newcr12 = ARCH_DEP(trace_pc) (pctea, regs);
|
|
#endif
|
|
|
|
/* [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 + 0 );
|
|
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_001_ZARCH_INSTALLED_FACILITY )
|
|
/* 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
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
&& (ete[4] & ETE4_G) == 0
|
|
#endif
|
|
&& (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_001_ZARCH_INSTALLED_FACILITY )
|
|
akm = ete[2] & ETE2_AKM;
|
|
#else
|
|
akm = ete[0] & ETE0_AKM;
|
|
#endif
|
|
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
pasn = ete[2] & ETE2_ASN;
|
|
#else
|
|
pasn = ete[0] & ETE0_ASN;
|
|
#endif
|
|
|
|
/* 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 );
|
|
|
|
#if defined( FEATURE_SUBSPACE_GROUP )
|
|
/* Perform subspace replacement on new PSTD */
|
|
pstd = ARCH_DEP( subspace_replace )( pstd, pasteo, NULL, regs );
|
|
#endif
|
|
|
|
} /* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
regs->GR_G( 14 ) = PSW_IA_FROM_IP( regs, 0 ) | PROBSTATE( ®s->psw );
|
|
else
|
|
#endif
|
|
regs->GR_L( 14 ) = (regs->psw.amode ? 0x80000000 : 0)
|
|
| PSW_IA_FROM_IP( regs, 0 ) | PROBSTATE( ®s->psw );
|
|
|
|
/* Set the breaking event address register */
|
|
SET_BEAR_REG( regs, regs->ip - 4 );
|
|
|
|
/* Update the PSW from the entry table */
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
SET_PSW_IA_AND_MAYBE_IP( 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;
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, ete[1] & ETE1_EIA );
|
|
}
|
|
#else
|
|
regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0;
|
|
regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24;
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, ete[1] & ETE1_EIA );
|
|
#endif
|
|
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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
regs->GR_H( 4 ) = ete[6];
|
|
regs->GR_L( 4 ) = ete[7];
|
|
#else
|
|
regs->GR_L( 4 ) = ete[2];
|
|
#endif
|
|
|
|
} /* 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 );
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY ) */
|
|
#endif /* defined( 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_FROM_IP( regs, 0 );
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
retn |= 0x01;
|
|
else
|
|
#endif
|
|
if (regs->psw.amode)
|
|
retn |= 0x80000000;
|
|
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
/* 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
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (ete[4] & ETE4_G)
|
|
{
|
|
regs->psw.amode64 = 1;
|
|
regs->psw.amode = 1;
|
|
regs->psw.AMASK = AMASK64;
|
|
SET_PSW_IA_AND_MAYBE_IP( 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;
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, ete[1] & ETE1_EIA );
|
|
}
|
|
#else
|
|
regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0;
|
|
regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24;
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, ete[1] & ETE1_EIA );
|
|
#endif
|
|
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_001_ZARCH_INSTALLED_FACILITY )
|
|
if (regs->psw.amode64)
|
|
regs->GR_H( 4 ) = ete[6];
|
|
regs->GR_L( 4 ) = ete[7];
|
|
#else
|
|
regs->GR_L( 4 ) = ete[2];
|
|
#endif
|
|
|
|
} /* end if (stacking PC) */
|
|
#else
|
|
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) */
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
/* Update trace table address if ASN or Mode switch made trace entry */
|
|
if (newcr12)
|
|
regs->CR( 12 ) = newcr12;
|
|
#endif
|
|
|
|
/* 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 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, 0x1802 ); // GR 3, 4 and 14
|
|
|
|
} /* 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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
UNREFERENCED( inst );
|
|
SIE_XC_INTERCEPT( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC3, PR ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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 - (likely( !newregs.execflag ) ? 2 :
|
|
newregs.exrl ? 6 : 4) );
|
|
|
|
/* 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 );
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
/* 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
|
|
#endif
|
|
/* 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);
|
|
|
|
#if defined( 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_001_ZARCH_INSTALLED_FACILITY )
|
|
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
|
|
#endif /* defined( 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;
|
|
|
|
#if defined( FEATURE_SUBSPACE_GROUP )
|
|
/* Perform subspace replacement on new PSTD */
|
|
newregs.CR(1) = ARCH_DEP( subspace_replace )( newregs.CR(1),
|
|
pasteo, NULL, &newregs );
|
|
#endif
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
#if defined( FEATURE_SUBSPACE_GROUP )
|
|
/* Perform subspace replacement on new SSTD */
|
|
newregs.CR(7) = ARCH_DEP( subspace_replace )( newregs.CR(7),
|
|
sasteo, NULL, &newregs );
|
|
#endif
|
|
|
|
} /* end else(sasn!=pasn) */
|
|
|
|
} /* end if (LSED_UET_PC) */
|
|
|
|
/* Update the updated CPU registers from the working copy */
|
|
memcpy( ®s->psw, &newregs.psw, sizeof( newregs.psw ));
|
|
memcpy( regs->gr, newregs.gr, sizeof( newregs.gr ));
|
|
memcpy( regs->cr_struct, newregs.cr_struct, sizeof( newregs.cr_struct ));
|
|
memcpy( regs->ar, newregs.ar, sizeof( newregs.ar ));
|
|
regs->bear = newregs.bear;
|
|
|
|
/* Set the main storage reference and change bits */
|
|
ARCH_DEP( or_storage_key )( alsed, (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 (1
|
|
&& IS_IC_PER_SA( &newregs )
|
|
&& !IS_PER_SUPRESS( &newregs, CR9_SA )
|
|
)
|
|
{
|
|
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 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, 0x3FFE ); // GR 2-14
|
|
|
|
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 */
|
|
#if defined( FEATURE_TRACING )
|
|
CREG newcr12 = 0; /* CR12 upon completion */
|
|
#endif
|
|
|
|
SIE_XC_INTERCEPT( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC2, PT ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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( ®s->psw )
|
|
|| !PRIMARY_SPACE_MODE( ®s->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 );
|
|
|
|
#if defined( 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
|
|
|
|
/* Determine instruction address, amode, and problem state */
|
|
#if defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
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_001_ZARCH_INSTALLED_FACILITY ) */
|
|
{
|
|
/* 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_001_ZARCH_INSTALLED_FACILITY )
|
|
aste[3] = ARCH_DEP( fetch_fullword_absolute )( abs+12, regs );
|
|
#else
|
|
aste[6] = ARCH_DEP( fetch_fullword_absolute )( abs+24, regs );
|
|
#endif
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
/* 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 );
|
|
|
|
#if defined( FEATURE_SUBSPACE_GROUP )
|
|
/* Perform subspace replacement on new PSTD */
|
|
pstd = ARCH_DEP( subspace_replace )( pstd, pasteo, NULL, regs );
|
|
#endif
|
|
|
|
/* 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 (PT-ss or PTI-ss) */
|
|
else
|
|
{
|
|
/* For PT-cp or PTI-cp use current primary STD or ASCE */
|
|
pstd = regs->CR( 1 );
|
|
}
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
/* Update trace table address if ASN tracing is on */
|
|
if (regs->CR( 12 ) & CR12_ASNTRACE)
|
|
regs->CR( 12 ) = newcr12;
|
|
#endif
|
|
|
|
/* 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;
|
|
SET_PSW_IA_AND_MAYBE_IP( 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_001_ZARCH_INSTALLED_FACILITY )
|
|
regs->psw.amode64 ? AMASK64 :
|
|
#endif
|
|
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 );
|
|
}
|
|
|
|
/* 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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
ARCH_DEP( program_transfer_proc )( regs, r1, r2, 0 );
|
|
}
|
|
#endif /* defined( FEATURE_DUAL_ADDRESS_SPACE ) */
|
|
|
|
|
|
#if defined( FEATURE_006_ASN_LX_REUSE_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* B99E PTI - Program Transfer with Instance [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( program_transfer_with_instance )
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
ARCH_DEP( program_transfer_proc )( regs, r1, r2, 1 );
|
|
}
|
|
#endif /* defined( FEATURE_006_ASN_LX_REUSE_FACILITY ) */
|
|
|
|
|
|
#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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
#if defined( FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE )
|
|
/* This instruction is executed as a no-operation in XC mode */
|
|
if (SIE_STATE_BIT_ON( regs, MX, XC ))
|
|
return;
|
|
#endif
|
|
|
|
PRIV_CHECK( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC1, PXLB ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
#if defined( FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE )
|
|
/* This instruction is executed as a no-operation in XC mode */
|
|
if (SIE_STATE_BIT_ON( regs, MX, XC ))
|
|
return;
|
|
#endif
|
|
|
|
PRIV_CHECK( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC1, PXLB ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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 pageaddr; /* Operand-2 page address */
|
|
BYTE oldkey; /* Original Storage key */
|
|
|
|
S( inst, regs, b2, effective_addr2 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_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
|
|
|
|
PRIV_CHECK( regs );
|
|
|
|
/* Load 2K block real address from operand address */
|
|
pageaddr = effective_addr2 & 0x00FFF800;
|
|
|
|
/* Convert real address to absolute address */
|
|
pageaddr = APPLY_PREFIXING( pageaddr, regs->PX );
|
|
|
|
/* Addressing exception if block is outside main storage */
|
|
if (pageaddr > regs->mainlim)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_ADDRESSING_EXCEPTION );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_MODE( regs ))
|
|
{
|
|
if (SIE_STATE_BIT_ON( regs, IC2, RRBE ))
|
|
SIE_INTERCEPT( regs );
|
|
|
|
if (!regs->sie_pref)
|
|
{
|
|
#if defined( _FEATURE_STORAGE_KEY_ASSIST )
|
|
if (1
|
|
&& SIE_STATE_BIT_ON( regs, RCPO0, ASIST )
|
|
&& SIE_STATE_BIT_ON( regs, RCPO2, RCPBY )
|
|
)
|
|
{
|
|
/* When "bypass use of RCP table" is requested
|
|
the guest page is assumed to be accessible.
|
|
*/
|
|
/* Translate guest absolute to host absolute */
|
|
SIE_TRANSLATE( &pageaddr, ACCTYPE_SIE, regs );
|
|
|
|
/* Save the original storage key */
|
|
oldkey = ARCH_DEP( get_2K_storage_key )( pageaddr );
|
|
|
|
/* Reset the reference bit in the real page */
|
|
ARCH_DEP( and_2K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
else // use RCP...(and possibly PGSTE)
|
|
#endif
|
|
{
|
|
PGSTE* pgste;
|
|
RCPTE* rcpte;
|
|
|
|
ARCH_DEP( GetPGSTE_and_RCPTE )( regs, pageaddr, &pgste, &rcpte );
|
|
|
|
OBTAIN_KEYLOCK( pgste, rcpte, regs );
|
|
{
|
|
int sr;
|
|
BYTE realkey;
|
|
|
|
/* Translate guest absolute address to host real */
|
|
sr = SIE_TRANSLATE_ADDR( regs->sie_mso + pageaddr,
|
|
USE_PRIMARY_SPACE,
|
|
HOSTREGS, ACCTYPE_SIE );
|
|
if (sr == 0)
|
|
{
|
|
/* Translate host real to host absolute */
|
|
pageaddr = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
/* Save original key before modifying */
|
|
realkey = ARCH_DEP( get_2K_storage_key )( pageaddr );
|
|
}
|
|
else
|
|
realkey = 0;
|
|
|
|
/* Save the page's real R/C bits by OR'ing them
|
|
into the host's R/C set in the RCP byte */
|
|
rcpte->rcpbyte |= ((realkey << 4) & RCPHOST);
|
|
|
|
/* The CC is determined from the logical 'OR'
|
|
of the real page's R/C bits and the guest's
|
|
R/C bits from the RCP area byte */
|
|
oldkey = realkey | (rcpte->rcpbyte & RCPGUEST);
|
|
|
|
/* Update the guest RCP bits */
|
|
rcpte->rcpbyte &= ~( RCPGUEST);
|
|
rcpte->rcpbyte |= (oldkey & RCPGUEST);
|
|
|
|
/* Reset the reference bit in the guest RCP set */
|
|
rcpte->rcpbyte &= ~RCPGREF;
|
|
|
|
/* Reset the reference bit in the real page */
|
|
if (sr == 0)
|
|
ARCH_DEP( and_2K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
}
|
|
}
|
|
else /* sie_perf */
|
|
{
|
|
/* Save the original storage key */
|
|
oldkey = ARCH_DEP( get_2K_storage_key )( pageaddr );
|
|
|
|
/* Reset the reference bit in the storage key */
|
|
ARCH_DEP( and_2K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
}
|
|
else /* !SIE_MODE */
|
|
#endif /* defined( _FEATURE_SIE ) */
|
|
{
|
|
/* Save the original storage key */
|
|
oldkey = ARCH_DEP( get_2K_storage_key )( pageaddr );
|
|
|
|
/* Reset the reference bit in the storage key */
|
|
ARCH_DEP( and_2K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
|
|
/* Set the condition code according to the state of the
|
|
reference and change bits in the ORIGINAL storage key:
|
|
|
|
0 Reference bit zero; change bit zero
|
|
1 Reference bit zero; change bit one
|
|
2 Reference bit one; change bit zero
|
|
3 Reference bit one; change bit one
|
|
*/
|
|
regs->psw.cc =
|
|
((oldkey & STORKEY_REF) ? 2 : 0)
|
|
| ((oldkey & 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 (oldkey & STORKEY_REF)
|
|
STORKEY_INVALIDATE( regs, pageaddr );
|
|
} /* end DEF_INST( reset_reference_bit ) */
|
|
#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 pageaddr; /* Operand-2 page address */
|
|
BYTE oldkey; /* Original Storage key */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
/* Load 4K block real address from r2 register */
|
|
pageaddr = regs->GR( r2 ) & ADDRESS_MAXWRAP_E(regs);
|
|
|
|
/* Convert real address to absolute address */
|
|
pageaddr = APPLY_PREFIXING( pageaddr, regs->PX );
|
|
|
|
/* Addressing exception if block is outside main storage */
|
|
if (pageaddr > regs->mainlim)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_ADDRESSING_EXCEPTION );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_MODE( regs ))
|
|
{
|
|
if (SIE_STATE_BIT_ON( regs, IC2, RRBE ))
|
|
SIE_INTERCEPT( regs );
|
|
|
|
if (!regs->sie_pref)
|
|
{
|
|
#if defined( _FEATURE_STORAGE_KEY_ASSIST )
|
|
if (1
|
|
&& (0
|
|
|| SIE_STATE_BIT_ON( regs, RCPO0, ASIST )
|
|
#if defined( _FEATURE_ZSIE )
|
|
// SKA is always active for z/VM
|
|
|| ARCH_900_IDX == HOSTREGS->arch_mode
|
|
#endif
|
|
)
|
|
&& SIE_STATE_BIT_ON( regs, RCPO2, RCPBY )
|
|
)
|
|
{
|
|
/* When "bypass use of RCP table" is requested
|
|
the guest page is assumed to be accessible.
|
|
*/
|
|
/* Translate guest absolute to host absolute */
|
|
SIE_TRANSLATE( &pageaddr, ACCTYPE_SIE, regs );
|
|
|
|
/* Save the original storage key */
|
|
oldkey = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
|
|
/* Reset the reference bit in the real page */
|
|
ARCH_DEP( and_4K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
else // use RCP...(and possibly PGSTE)
|
|
#endif
|
|
{
|
|
PGSTE* pgste;
|
|
RCPTE* rcpte;
|
|
|
|
ARCH_DEP( GetPGSTE_and_RCPTE )( regs, pageaddr, &pgste, &rcpte );
|
|
|
|
OBTAIN_KEYLOCK( pgste, rcpte, regs );
|
|
{
|
|
int sr;
|
|
BYTE realkey;
|
|
|
|
/* Translate guest absolute address to host real */
|
|
sr = SIE_TRANSLATE_ADDR( regs->sie_mso + pageaddr,
|
|
USE_PRIMARY_SPACE,
|
|
HOSTREGS, ACCTYPE_SIE );
|
|
if (sr == 0)
|
|
{
|
|
/* Translate host real to host absolute */
|
|
pageaddr = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
/* Save original key before modifying */
|
|
realkey = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
}
|
|
else
|
|
realkey = 0;
|
|
|
|
/* Save the page's real R/C bits by OR'ing them
|
|
into the host's R/C set in the RCP byte */
|
|
rcpte->rcpbyte |= ((realkey << 4) & RCPHOST);
|
|
|
|
/* The CC is determined from the logical 'OR'
|
|
of the real page's R/C bits and the guest's
|
|
R/C bits from the RCP area byte */
|
|
oldkey = realkey | (rcpte->rcpbyte & RCPGUEST);
|
|
|
|
/* Update the guest RCP bits */
|
|
rcpte->rcpbyte &= ~( RCPGUEST);
|
|
rcpte->rcpbyte |= (oldkey & RCPGUEST);
|
|
|
|
/* Reset the reference bit in the guest RCP set */
|
|
rcpte->rcpbyte &= ~RCPGREF;
|
|
|
|
/* Reset the reference bit in the real page */
|
|
if (sr == 0)
|
|
ARCH_DEP( and_4K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
}
|
|
}
|
|
else /* sie_pref */
|
|
{
|
|
/* Save the original storage key */
|
|
oldkey = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
|
|
/* Reset the reference bit in the storage key */
|
|
ARCH_DEP( and_4K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
}
|
|
else /* !SIE_MODE */
|
|
#endif /* defined( _FEATURE_SIE ) */
|
|
{
|
|
/* Save the original storage key */
|
|
oldkey = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
|
|
/* Reset the reference bit in the storage key */
|
|
ARCH_DEP( and_4K_storage_key )( pageaddr, STORKEY_REF );
|
|
}
|
|
|
|
/* Set the condition code according to the state of the
|
|
reference and change bits in the ORIGINAL storage key:
|
|
|
|
0 Reference bit zero; change bit zero
|
|
1 Reference bit zero; change bit one
|
|
2 Reference bit one; change bit zero
|
|
3 Reference bit one; change bit one
|
|
*/
|
|
regs->psw.cc =
|
|
((oldkey & STORKEY_REF) ? 2 : 0)
|
|
| ((oldkey & 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 (oldkey & STORKEY_REF)
|
|
STORKEY_INVALIDATE( regs, pageaddr );
|
|
|
|
} /* 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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
#if defined( FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST )
|
|
if (inst[1] == 0x19) // SAC only
|
|
#endif
|
|
{
|
|
/* 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( ®s->psw )
|
|
|| (regs->CR( 0 ) & CR0_SEC_SPACE) == 0)
|
|
#if defined( FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE )
|
|
&& !SIE_STATE_BIT_ON( regs, MX, XC )
|
|
#endif
|
|
)
|
|
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_STATE_BIT_ON( regs, MX, XC )
|
|
&& (mode == 1 || mode == 3) )
|
|
#endif
|
|
)
|
|
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
|
|
{
|
|
/* 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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
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 (get_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"PRIX64"\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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
DW_CHECK( effective_addr2, regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC3, SCKC ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* Fetch clock comparator value from operand location */
|
|
dreg = ARCH_DEP( vfetch8 )( effective_addr2, b2, regs );
|
|
|
|
// /*debug*/LOGMSG( "Set clock comparator=%16.16"PRIX64"\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 (get_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 );
|
|
|
|
UNREFERENCED( inst );
|
|
|
|
TXF_INSTR_CHECK( 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 );
|
|
}
|
|
#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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
DW_CHECK( effective_addr2, regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC3, SPT ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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 (unlikely( dreg < 0 ))
|
|
ON_IC_PTIMER( regs );
|
|
else
|
|
OFF_IC_PTIMER( regs );
|
|
}
|
|
RELEASE_INTLOCK( regs );
|
|
|
|
// /*debug*/LOGMSG( "Set CPU timer=%16.16"PRIX64"\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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
SIE_INTERCEPT( regs );
|
|
FW_CHECK( effective_addr2, regs );
|
|
|
|
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
|
|
}
|
|
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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
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 */
|
|
#if defined( FEATURE_TRACING )
|
|
CREG newcr12 = 0; /* CR12 upon completion */
|
|
#endif
|
|
|
|
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( ®s->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 );
|
|
|
|
#if defined( 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
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
/* 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];
|
|
|
|
#if defined( FEATURE_SUBSPACE_GROUP )
|
|
/* Perform subspace replacement on new SSTD */
|
|
sstd = ARCH_DEP( subspace_replace )( sstd, sasteo, NULL, regs );
|
|
#endif
|
|
|
|
} /* end if (SSAR-ss or SSAIR-ss) */
|
|
|
|
#if defined( FEATURE_TRACING )
|
|
/* Update trace table address if ASN tracing is on */
|
|
if (regs->CR( 12 ) & CR12_ASNTRACE)
|
|
regs->CR( 12 ) = newcr12;
|
|
#endif
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* 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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
ARCH_DEP( set_secondary_asn_proc )( regs, r1, r2, 0 );
|
|
}
|
|
#endif /* defined( FEATURE_DUAL_ADDRESS_SPACE ) */
|
|
|
|
|
|
#if defined( FEATURE_006_ASN_LX_REUSE_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* B99F SSAIR - Set Secondary ASN with Instance [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( set_secondary_asn_with_instance )
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
|
|
RRE( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
ARCH_DEP( set_secondary_asn_proc )( regs, r1, r2, 1 );
|
|
}
|
|
#endif /* defined( FEATURE_006_ASN_LX_REUSE_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_BASIC_STORAGE_KEYS )
|
|
/*-------------------------------------------------------------------*/
|
|
/* 08 SSK - Set Storage Key [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( set_storage_key )
|
|
{
|
|
int r1, r2; /* Operand register numbers */
|
|
RADR pageaddr; /* Working abs page address */
|
|
BYTE r1key; /* Key value to set from r1 */
|
|
|
|
RR( inst, regs, r1, r2 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
/* Special Operation Exception if Storkey exception control zero */
|
|
#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
|
|
|
|
/* Key to be applied */
|
|
r1key = regs->GR_LHLCL( r1 );
|
|
|
|
/* 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 real address from r2 register */
|
|
pageaddr = regs->GR_L( r2 ) & 0x00FFF800;
|
|
|
|
/* Convert real address to absolute address */
|
|
pageaddr = APPLY_PREFIXING( pageaddr, regs->PX );
|
|
|
|
/* Addressing exception if block is outside of main storage */
|
|
if (pageaddr > regs->mainlim)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_ADDRESSING_EXCEPTION );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_MODE( regs ))
|
|
{
|
|
if (SIE_STATE_BIT_ON( regs, IC2, SSKE ))
|
|
SIE_INTERCEPT( regs );
|
|
|
|
if (!regs->sie_pref)
|
|
{
|
|
#if defined( _FEATURE_STORAGE_KEY_ASSIST )
|
|
if (1
|
|
&& SIE_STATE_BIT_ON( regs, RCPO0, ASIST )
|
|
&& SIE_STATE_BIT_ON( regs, RCPO2, RCPBY )
|
|
)
|
|
{
|
|
/* When "bypass use of RCP table" is requested
|
|
the guest page is assumed to be accessible.
|
|
*/
|
|
/* Translate guest absolute to host absolute */
|
|
SIE_TRANSLATE( &pageaddr, ACCTYPE_SIE, regs );
|
|
|
|
/* Set the storage key as requested */
|
|
ARCH_DEP( put_4K_storage_key )( pageaddr, r1key );
|
|
}
|
|
else // use RCP...(and possibly PGSTE)
|
|
#endif
|
|
{
|
|
PGSTE* pgste;
|
|
RCPTE* rcpte;
|
|
int sr;
|
|
BYTE oldkey;
|
|
|
|
ARCH_DEP( GetPGSTE_and_RCPTE )( regs, pageaddr, &pgste, &rcpte );
|
|
|
|
OBTAIN_KEYLOCK( pgste, rcpte, regs );
|
|
{
|
|
/* Translate guest absolute address to host real.
|
|
Note that the RCP table MUST be locked BEFORE
|
|
we try to access the real page!
|
|
*/
|
|
sr = SIE_TRANSLATE_ADDR( regs->sie_mso + pageaddr,
|
|
USE_PRIMARY_SPACE,
|
|
HOSTREGS, ACCTYPE_SIE );
|
|
if (sr == 0)
|
|
{
|
|
/* Translate host real to host absolute */
|
|
pageaddr = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
/* Save the original key */
|
|
oldkey = ARCH_DEP( get_4K_storage_key )( pageaddr );
|
|
|
|
/* Before potentially changing the real page's
|
|
key, save it's real R/C bits by OR'ing them
|
|
into the host set's R/C bits in the RCP byte
|
|
*/
|
|
rcpte->rcpbyte |= ((oldkey << 4) & RCPHOST);
|
|
}
|
|
else // (sr != 0)
|
|
{
|
|
/* If the real page is inaccessible and SKA
|
|
is not active, then we cannot proceed since,
|
|
with the old non-SKA RCP table approach,
|
|
there isn't any other way to set or obtain
|
|
the page's access key and fetch-protect bits
|
|
since the old non-SKA RCP table contains
|
|
ONLY the R/C bits, but not anything else.
|
|
*/
|
|
if (!pgste)
|
|
{
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
SIE_INTERCEPT( regs );
|
|
}
|
|
|
|
/* Reconstruct the original storage key from
|
|
both the PGSTE and RCPTE entries.
|
|
*/
|
|
oldkey = (pgste->pgsvkey & PGSVKACF)
|
|
| (rcpte->rcpbyte & RCPGUEST);
|
|
}
|
|
|
|
/* Update the R/C bits in the RCP */
|
|
rcpte->rcpbyte &= ~( RCPGUEST);
|
|
rcpte->rcpbyte |= (r1key & RCPGUEST);
|
|
|
|
/* Update the other bits... */
|
|
if (pgste)
|
|
{
|
|
/* Save updated key in PGSTE */
|
|
pgste->pgsvkey = (r1key & PGSVKACF);
|
|
|
|
/* SIE *requires* the R/C bits be cleared to
|
|
zero in the real page if still accessible.
|
|
Otherwise if not still accessible, that's
|
|
okay since we've honored the guest's "SSK"
|
|
request by setting the updated key in the
|
|
above PGSTE pgsvkey field as well as the
|
|
R/C bits too in the RCPTE byte.
|
|
*/
|
|
if (sr == 0)
|
|
{
|
|
/* Clear real page's R/C bits to zero */
|
|
r1key &= ~(STORKEY_REF | STORKEY_CHANGE);
|
|
}
|
|
}
|
|
|
|
/* Update real page's key BEFORE releasing lock */
|
|
if (sr == 0)
|
|
ARCH_DEP( put_4K_storage_key )( pageaddr, r1key );
|
|
}
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
}
|
|
}
|
|
else /* sie_pref */
|
|
{
|
|
/* Update the storage key from r1 register bits 24-30 */
|
|
ARCH_DEP( put_4K_storage_key )( pageaddr, r1key );
|
|
}
|
|
}
|
|
else /* !SIE_MODE */
|
|
#endif /* defined( _FEATURE_SIE ) */
|
|
{
|
|
/* Update the storage key from r1 register bits 24-30 */
|
|
ARCH_DEP( put_2K_storage_key )( pageaddr, r1key );
|
|
}
|
|
|
|
/* Invalidate AIA/AEA so that the REF and CHANGE bits
|
|
will be set when referenced next */
|
|
STORKEY_INVALIDATE( regs, pageaddr );
|
|
|
|
// /*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_010_CONDITIONAL_SSKE_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* SUBROUTINE TO PERFORM CONDITIONAL SSKE PROCESSING */
|
|
/*-------------------------------------------------------------------*/
|
|
/* Input: */
|
|
/* */
|
|
/* sske true = SSKE, false = PFMF */
|
|
/* regs Register context */
|
|
/* r1 Operand-1 register number */
|
|
/* m3 Operand-3 mask field from SSKE instruction. */
|
|
/* oldkey Contents of storage key before modification */
|
|
/* r1key Register r1 storage key comparison value */
|
|
/* */
|
|
/* Output (when conditional SSKE facility is *NOT* installed): */
|
|
/* */
|
|
/* r1 register and condition code remain unchanged, */
|
|
/* and the return value is false (update key normally). */
|
|
/* */
|
|
/* Output (when conditional SSKE facility *IS* installed): */
|
|
/* */
|
|
/* SSKE: */
|
|
/* */
|
|
/* r1 register bits 48-55 set to original storage key value; */
|
|
/* */
|
|
/* - if storage key *SHOULD* be updated, the condition */
|
|
/* code is set to 1 and the function return code value */
|
|
/* is false: do normal key update processing. */
|
|
/* */
|
|
/* - if storage key update should be BYPASSED, the condition */
|
|
/* code is set to 0 and the function return code value */
|
|
/* is true: no change should be made to the storage key. */
|
|
/* */
|
|
/* PFMF: */
|
|
/* */
|
|
/* r1 register remains unchanged; */
|
|
/* */
|
|
/* - if storage key *SHOULD* be updated, the condition */
|
|
/* code remains unchanged and the function return value */
|
|
/* is false: do normal key update processing. */
|
|
/* */
|
|
/* - if storage key update should be BYPASSED, the condition */
|
|
/* code remains unchanged and the function return value */
|
|
/* is true: no change should be made to the storage key. */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
bool ARCH_DEP( conditional_sske_procedure )( bool sske, REGS* regs,
|
|
int r1, int m3,
|
|
BYTE oldkey, BYTE r1key )
|
|
{
|
|
/* Perform normal SSKE processing if Conditional-SSKE Facility
|
|
is not installed or the both MR and MC bits are zero. Else
|
|
perform Conditional-SSKE processing if facility is installed
|
|
and either of the MR or MC bits are non-zero.
|
|
*/
|
|
if (0
|
|
|| !FACILITY_ENABLED( 010_CONDITIONAL_SSKE, regs )
|
|
|| (m3 & (SSKE_MASK_MR | SSKE_MASK_MC)) == 0
|
|
)
|
|
return false; /* Update key normally */
|
|
|
|
/* Insert original storage key into R1 register bits 48-55 */
|
|
if (sske)
|
|
regs->GR_LHLCH( r1 ) = oldkey;
|
|
|
|
/* Determine whether key update should be bypassed or not */
|
|
if (bypass_skey_update( regs, m3, oldkey, r1key ))
|
|
{
|
|
if (sske)
|
|
regs->psw.cc = 0; /* cc0: storage key NOT set */
|
|
return true; /**** BYPASS key update! ****/
|
|
}
|
|
else
|
|
{
|
|
if (sske)
|
|
regs->psw.cc = 1; /* cc1: entire storage key set */
|
|
return false; /* Update storage key normally */
|
|
}
|
|
} /* end function conditional_sske_procedure */
|
|
#endif /* defined( _FEATURE_010_CONDITIONAL_SSKE_FACILITY ) */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* sske_or_pfmf_procedure */
|
|
/*-------------------------------------------------------------------*/
|
|
/* Common helper function used by both SSKE and PFMF instructions. */
|
|
/*-------------------------------------------------------------------*/
|
|
void ARCH_DEP( sske_or_pfmf_procedure )
|
|
(
|
|
bool sske, /* true = SSKE call, false = PFMF */
|
|
bool intlocked, /* true = INTLOCK held; false otherwise */
|
|
REGS* regs, /* Registers context */
|
|
U64 abspage, /* Absolute address of 4K page frame */
|
|
int r1, /* Operand-1 register number */
|
|
int m3, /* Mask field from SSKE instruction,
|
|
or PFMF register r1 bits 52-55. */
|
|
BYTE r1key /* Frame's POTENTIALLY new key value */
|
|
)
|
|
{
|
|
BYTE oldkey; /* Original key before setting */
|
|
bool set_key; /* SSKE or PFMF set key option */
|
|
bool clear_frame; /* PFMF clear frame option */
|
|
bool replace_key = false; /* Work flag to make things simpler */
|
|
bool key_updated = false; /* Work flag to make things simpler */
|
|
|
|
#if !defined( FEATURE_010_CONDITIONAL_SSKE_FACILITY )
|
|
UNREFERENCED( m3 );
|
|
#endif
|
|
|
|
/* Addressing exception if block is outside of main storage */
|
|
if (abspage > regs->mainlim)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_ADDRESSING_EXCEPTION );
|
|
|
|
set_key = ( sske || (regs->GR( r1 ) & PFMF_FMFI_SK));
|
|
clear_frame = (!sske && (regs->GR( r1 ) & PFMF_FMFI_CF));
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_MODE( regs ))
|
|
{
|
|
if (SIE_STATE_BIT_ON( regs, IC2, SSKE ))
|
|
SIE_INTERCEPT( regs );
|
|
|
|
if (!regs->sie_pref)
|
|
{
|
|
#if defined( _FEATURE_STORAGE_KEY_ASSIST )
|
|
if (1
|
|
&& (0
|
|
|| SIE_STATE_BIT_ON( regs, RCPO0, ASIST )
|
|
#if defined( _FEATURE_ZSIE )
|
|
// SKA is always active for z/VM
|
|
|| ARCH_900_IDX == HOSTREGS->arch_mode
|
|
#endif
|
|
)
|
|
&& SIE_STATE_BIT_ON( regs, RCPO2, RCPBY )
|
|
)
|
|
{
|
|
/* When "bypass use of RCP table" is requested
|
|
the guest page is assumed to be accessible.
|
|
*/
|
|
/* Translate guest absolute to host absolute */
|
|
SIE_TRANSLATE( &abspage, ACCTYPE_SIE, regs );
|
|
replace_key = set_key;
|
|
}
|
|
else // use RCP...(and possibly PGSTE)
|
|
#endif /* defined( _FEATURE_STORAGE_KEY_ASSIST ) */
|
|
{
|
|
PGSTE* pgste;
|
|
RCPTE* rcpte;
|
|
int sr;
|
|
|
|
ARCH_DEP( GetPGSTE_and_RCPTE )( regs, abspage, &pgste, &rcpte );
|
|
|
|
OBTAIN_KEYLOCK( pgste, rcpte, regs );
|
|
{
|
|
/* Translate guest absolute address to host real.
|
|
Note that the RCP table MUST be locked BEFORE
|
|
we try to access the real page!
|
|
*/
|
|
sr = SIE_TRANSLATE_ADDR( regs->sie_mso + abspage,
|
|
USE_PRIMARY_SPACE,
|
|
HOSTREGS, ACCTYPE_SIE );
|
|
if (sr == 0)
|
|
{
|
|
/* Translate host real to host absolute */
|
|
abspage = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
if (set_key)
|
|
{
|
|
/* Save the original key */
|
|
oldkey = ARCH_DEP( get_4K_storage_key )( abspage );
|
|
}
|
|
}
|
|
else // (sr != 0)
|
|
{
|
|
/* If the real page is inaccessible and SKA
|
|
is not active, then we cannot proceed since,
|
|
with the old non-SKA RCP table approach,
|
|
there isn't any other way to set or obtain
|
|
the page's access key and fetch-protect bits
|
|
since the old non-SKA RCP table contains
|
|
ONLY the R/C bits, but not anything else.
|
|
|
|
We also can't proceed if this is a PFMF call
|
|
and clear frame was specified since we need
|
|
access to the real page frame for that too.
|
|
*/
|
|
if (!pgste || clear_frame)
|
|
{
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
SIE_INTERCEPT( regs );
|
|
}
|
|
|
|
/* Reconstruct the original storage key from
|
|
both the PGSTE and RCPTE entries.
|
|
*/
|
|
if (set_key)
|
|
{
|
|
oldkey = (pgste->pgsvkey & PGSVKACF)
|
|
| (rcpte->rcpbyte & RCPGUEST);
|
|
}
|
|
}
|
|
|
|
if (set_key)
|
|
{
|
|
#if defined( FEATURE_010_CONDITIONAL_SSKE_FACILITY )
|
|
if (!ARCH_DEP( conditional_sske_procedure )
|
|
( sske, regs, r1, m3, oldkey, r1key ))
|
|
#endif
|
|
{
|
|
/* Update the R/C bits in the RCP */
|
|
rcpte->rcpbyte &= ~( RCPGUEST);
|
|
rcpte->rcpbyte |= (r1key & RCPGUEST);
|
|
|
|
/* Update the other bits... */
|
|
if (pgste)
|
|
{
|
|
/* Save updated key in PGSTE */
|
|
pgste->pgsvkey = (r1key & PGSVKACF);
|
|
|
|
/* SIE *requires* the R/C bits be cleared to
|
|
zero in the real page if still accessible.
|
|
Otherwise if not still accessible, that's
|
|
okay since we've honored the guest's "SSK"
|
|
request by setting the updated key in the
|
|
above PGSTE pgsvkey field as well as the
|
|
R/C bits too in the RCPTE byte.
|
|
*/
|
|
if (sr == 0)
|
|
{
|
|
/* Clear real page's R/C bits to zero */
|
|
r1key &= ~(STORKEY_REF | STORKEY_CHANGE);
|
|
}
|
|
}
|
|
|
|
/* Update real page's key BEFORE releasing lock */
|
|
if (sr == 0)
|
|
{
|
|
/* Before updating the real page's key, update
|
|
the host's R/C bits in the RCP table entry.
|
|
*/
|
|
rcpte->rcpbyte |= ((oldkey << 4) & RCPHOST);
|
|
|
|
ARCH_DEP( put_4K_storage_key )( abspage, r1key );
|
|
key_updated = true;
|
|
replace_key = false; // (we just did it!)
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Clear the page frame to zeros if requested.
|
|
Note that the RCP table MUST be locked while
|
|
accessing the real page!
|
|
*/
|
|
if (clear_frame)
|
|
{
|
|
clear_page_4K( regs->mainstor + abspage );
|
|
clear_frame = false; // (don't do twice!)
|
|
}
|
|
}
|
|
RELEASE_KEYLOCK( pgste, rcpte, regs );
|
|
}
|
|
}
|
|
else /* sie_pref */
|
|
replace_key = set_key;
|
|
}
|
|
else /* !SIE_MODE */
|
|
#endif /* defined( _FEATURE_SIE ) */
|
|
replace_key = set_key;
|
|
|
|
if (replace_key)
|
|
{
|
|
#if defined( FEATURE_010_CONDITIONAL_SSKE_FACILITY )
|
|
BYTE oldkey = ARCH_DEP( get_4K_storage_key )( abspage );
|
|
if (!ARCH_DEP( conditional_sske_procedure )
|
|
( sske, regs, r1, m3, oldkey, r1key ))
|
|
#endif
|
|
{
|
|
ARCH_DEP( put_4K_storage_key )( abspage, r1key );
|
|
key_updated = true;
|
|
}
|
|
}
|
|
|
|
/* Clear the page frame to zeros if requested */
|
|
if (clear_frame)
|
|
clear_page_4K( regs->mainstor + abspage );
|
|
|
|
if (set_key)
|
|
{
|
|
/* Invalidate AIA/AEA so that the REF and CHANGE bits
|
|
will be set when referenced next */
|
|
if (intlocked)
|
|
STORKEY_INVALIDATE_LOCKED( regs, abspage );
|
|
else
|
|
STORKEY_INVALIDATE( regs, abspage );
|
|
}
|
|
|
|
#if defined( FEATURE_PER_STORAGE_KEY_ALTERATION_FACILITY )
|
|
/* Indicate PER Storage-key Alteration event if key was updated */
|
|
if (1
|
|
&& key_updated
|
|
&& EN_IC_PER_SKEY( regs )
|
|
&& PER_RANGE_CHECK( abspage, regs->CR( 10 ), regs->CR( 11 ) )
|
|
)
|
|
ON_IC_PER_SKEY( regs );
|
|
#endif
|
|
} /* end ARCH_DEP( sske_or_pfmf_procedure ) */
|
|
|
|
|
|
#if defined( FEATURE_EXTENDED_STORAGE_KEYS )
|
|
/*-------------------------------------------------------------------*/
|
|
/* B22B SSKE - Set Storage Key extended [RRF-c] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( set_storage_key_extended )
|
|
{
|
|
int r1, r2; /* Operand register numbers */
|
|
int m3; /* Operand-3 mask field */
|
|
RADR pageaddr; /* Working abs page address */
|
|
BYTE r1key; /* Key value to set from r1 */
|
|
|
|
#if defined( FEATURE_008_ENHANCED_DAT_FACILITY_1 )
|
|
int fc; /* Frame count (multi-block) */
|
|
bool multi_block = false; /* Work (simplifies things) */
|
|
BYTE original_cc = regs->psw.cc; /* (in case of multi-block) */
|
|
#endif
|
|
bool quiesce = false; /* Set Key should quiesce */
|
|
|
|
RRF_M( inst, regs, r1, r2, m3 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
/* Save key to MAYBE be set */
|
|
r1key = regs->GR_LHLCL( r1 );
|
|
|
|
/* Load real or absolute page address from r2 register */
|
|
pageaddr = regs->GR( r2 );
|
|
|
|
#if defined( FEATURE_008_ENHANCED_DAT_FACILITY_1 )
|
|
if (1
|
|
&& FACILITY_ENABLED( 008_EDAT_1, regs )
|
|
&& (m3 & SSKE_MASK_MB)
|
|
)
|
|
{
|
|
U64 low_end_of_range = (pageaddr & STORAGE_KEY_4K_PAGEMASK);
|
|
U64 hi_end_of_range = ROUND_UP( low_end_of_range+1,
|
|
ONE_MEGABYTE );
|
|
fc = (hi_end_of_range - low_end_of_range) / _4K;
|
|
multi_block = true;
|
|
}
|
|
else // (not multi-block)
|
|
{
|
|
fc = 1;
|
|
/* Convert real address to absolute address */
|
|
pageaddr = APPLY_PREFIXING( pageaddr, regs->PX );
|
|
}
|
|
#endif
|
|
|
|
/* Wrap address according to addressing mode */
|
|
pageaddr &= ADDRESS_MAXWRAP_E( regs );
|
|
|
|
PERFORM_SERIALIZATION( regs );
|
|
PERFORM_CHKPT_SYNC( regs );
|
|
|
|
#if defined( FEATURE_073_TRANSACT_EXEC_FACILITY )
|
|
/* TXF Key Quiescing support */
|
|
quiesce = FACILITY_ENABLED( 073_TRANSACT_EXEC, regs ) &&
|
|
(0
|
|
|| !FACILITY_ENABLED( 014_NONQ_KEY_SET, regs )
|
|
|| !(m3 & SSKE_MASK_NQ)
|
|
);
|
|
if (quiesce)
|
|
{
|
|
OBTAIN_INTLOCK( regs );
|
|
SYNCHRONIZE_CPUS( regs );
|
|
}
|
|
#endif
|
|
|
|
#if defined( FEATURE_008_ENHANCED_DAT_FACILITY_1 )
|
|
|
|
/* Process all pages within requested frame... */
|
|
while (fc--)
|
|
{
|
|
#endif
|
|
/* Use helper function to actually set the key or not */
|
|
ARCH_DEP( sske_or_pfmf_procedure )
|
|
(
|
|
true, /* true = SSKE call, false = PFMF */
|
|
quiesce, /* true = INTLOCK held; else false */
|
|
regs, /* Registers context */
|
|
pageaddr, /* Absolute address of 4K page frame */
|
|
r1, /* Operand-1 register number */
|
|
m3, /* Mask field from SSKE instruction,
|
|
or PFMF register r1 bits 52-55. */
|
|
r1key /* Frame's POTENTIALLY new key value */
|
|
);
|
|
|
|
#if defined( FEATURE_008_ENHANCED_DAT_FACILITY_1 )
|
|
|
|
/* Advance to next page if multi-block mode */
|
|
if (multi_block)
|
|
{
|
|
if (regs->psw.amode64)
|
|
{
|
|
regs->GR_G( r2 ) += STORAGE_KEY_4K_PAGESIZE;
|
|
regs->GR_G( r2 ) &= ADDRESS_MAXWRAP_E( regs );
|
|
}
|
|
else
|
|
{
|
|
regs->GR_L( r2 ) += STORAGE_KEY_4K_PAGESIZE;
|
|
regs->GR_L( r2 ) &= ADDRESS_MAXWRAP_E( regs );
|
|
}
|
|
pageaddr += STORAGE_KEY_4K_PAGESIZE;
|
|
pageaddr &= ADDRESS_MAXWRAP_E( regs );
|
|
}
|
|
|
|
} // end while...
|
|
|
|
if (multi_block)
|
|
{
|
|
if (m3 & (SSKE_MASK_MR | SSKE_MASK_MC))
|
|
regs->psw.cc = 3;
|
|
else
|
|
regs->psw.cc = original_cc;
|
|
}
|
|
|
|
#endif /* defined( FEATURE_008_ENHANCED_DAT_FACILITY_1 ) */
|
|
|
|
#if defined( FEATURE_073_TRANSACT_EXEC_FACILITY )
|
|
/* TXF Key Quiescing support */
|
|
if (quiesce)
|
|
{
|
|
txf_abort_all( regs->cpuad, TXF_WHY_STORKEY, PTT_LOC );
|
|
RELEASE_INTLOCK( regs );
|
|
}
|
|
#endif
|
|
|
|
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 [SI] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( set_system_mask )
|
|
{
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
S( inst, regs, b2, effective_addr2 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
/*
|
|
* ECPS:VM - Before checking for prob/priv
|
|
* Check CR6 to see if S-ASSIST is requested
|
|
*
|
|
* If we can process it, then do it
|
|
*/
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
#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_STATE_BIT_ON( regs, MX, XC )
|
|
#endif
|
|
)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIAL_OPERATION_EXCEPTION );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC1, SSM ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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_STATE_BIT_ON( regs, MX, XC )
|
|
&& (regs->psw.sysmask & PSW_DATMODE) )
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
#endif
|
|
|
|
/* 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
|
|
)
|
|
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-a] */
|
|
/*-------------------------------------------------------------------*/
|
|
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_001_ZARCH_INSTALLED_FACILITY ) || defined( FEATURE_HERCULES_DIAGCALLS )
|
|
int cpu; /* cpu number */
|
|
int set_arch = 0; /* Need to switch mode */
|
|
#endif /*defined( _900 ) || defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )*/
|
|
size_t log_sigp = 0; /* Log SIGP instruction flag */
|
|
char log_buf[128]; /* Log buffer */
|
|
|
|
RS( inst, regs, r1, r3, b2, effective_addr2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
SIE_INTERCEPT( regs );
|
|
|
|
/* 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);
|
|
|
|
PTT_SIG("SIGP",parm,cpad,order);
|
|
|
|
/* Return condition code 3 if target CPU does not exist */
|
|
if (cpad >= sysblk.maxcpu)
|
|
{
|
|
PTT_ERR("*SIGP",parm,cpad,order);
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
|
|
/* Issuing Sense to an offline CPU that is >= hicpu
|
|
now not considered unusual especially since
|
|
we have increased the default max CPU number to 8 */
|
|
if (order == SIGP_SENSE && !IS_CPU_ONLINE( cpad )
|
|
&& cpad >= sysblk.hicpu)
|
|
{
|
|
PTT_ERR("*SIGP",parm,cpad,order);
|
|
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 = MSGBUF( log_buf,
|
|
"%s%02X: SIGP %-32s (%2.2X) %s%02X, PARM "F_GREG,
|
|
PTYPSTR( regs->cpuad ), regs->cpuad,
|
|
order2name( order ), order,
|
|
PTYPSTR( cpad ), 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)
|
|
{
|
|
if (regs->insttrace && sysblk.traceFILE)
|
|
tf_0814( regs, order, 2, cpad, status, parm, 0 );
|
|
else
|
|
// "Processor %s: CC %d%s"
|
|
WRMSG( HHC00814, "I", log_buf, 2, "" );
|
|
}
|
|
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
|
|
&& !IS_CPU_ONLINE( cpad ))
|
|
{
|
|
RELEASE_INTLOCK( regs );
|
|
release_lock( &sysblk.sigplock );
|
|
regs->psw.cc = 3;
|
|
if (log_sigp)
|
|
{
|
|
if (regs->insttrace && sysblk.traceFILE)
|
|
tf_0814( regs, order, 3, cpad, status, parm, 0 );
|
|
else
|
|
// "Processor %s: CC %d%s"
|
|
WRMSG(HHC00814, "I", log_buf, 3, "");
|
|
}
|
|
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)
|
|
{
|
|
if (regs->insttrace && sysblk.traceFILE)
|
|
tf_0814( regs, order, 2, cpad, status, parm, 0 );
|
|
else
|
|
// "Processor %s: CC %d%s"
|
|
WRMSG( HHC00814, "I", log_buf, 2, "" );
|
|
}
|
|
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_001_ZARCH_INSTALLED_FACILITY )
|
|
|
|
case SIGP_COND_EMERGENCY:
|
|
|
|
/* Test for checkstop state */
|
|
if (tregs->checkstop)
|
|
status |= SIGP_STATUS_CHECK_STOP;
|
|
else
|
|
{
|
|
U16 check_asn = (parm & 0xFFFF);
|
|
|
|
MAYBE_SET_PSW_IA_FROM_IP( 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_001_ZARCH_INSTALLED_FACILITY ) */
|
|
|
|
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
|
|
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
|
|
|
|
/* Signal initial CPU reset function */
|
|
tregs->sigp_ini_reset = 1;
|
|
tregs->cpustate = CPUSTATE_STOPPING;
|
|
ON_IC_INTERRUPT( tregs );
|
|
|
|
break;
|
|
|
|
#if defined( FEATURE_S370_CHANNEL )
|
|
case SIGP_PR:
|
|
channelset_reset( tregs );
|
|
/* fallthrough*/
|
|
#endif
|
|
/* FALLTHRU */
|
|
case SIGP_RESET:
|
|
/* Signal CPU reset function */
|
|
tregs->sigp_reset = 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
|
|
/* 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
|
|
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 < 16; i++)
|
|
STORE_DW( tregs->mainstor + absx + (i*8), tregs->FPR_L(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_001_ZARCH_INSTALLED_FACILITY ) || defined( FEATURE_HERCULES_DIAGCALLS )
|
|
case SIGP_SETARCH:
|
|
|
|
/* CPU must have ESAME support */
|
|
if (!FACILITY_ENABLED( 001_ZARCH_INSTALLED, regs ))
|
|
status = SIGP_STATUS_INVALID_ORDER;
|
|
|
|
PERFORM_SERIALIZATION( regs );
|
|
PERFORM_CHKPT_SYNC( regs );
|
|
|
|
for (cpu = 0; cpu < sysblk.maxcpu; 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_001_ZARCH_INSTALLED_FACILITY )
|
|
|
|
case 0: // from: -- z/Arch --to--> 390
|
|
|
|
if (sysblk.arch_mode == ARCH_390_IDX)
|
|
status = SIGP_STATUS_INVALID_PARAMETER;
|
|
else
|
|
{
|
|
sysblk.arch_mode = ARCH_390_IDX;
|
|
set_arch = 1;
|
|
|
|
INVALIDATE_AIA( regs );
|
|
regs->captured_zpsw = regs->psw;
|
|
regs->psw.states |= BIT( PSW_NOTESAME_BIT );
|
|
regs->PX &= PX_900_MASK;
|
|
|
|
for (cpu = 0; cpu < sysblk.maxcpu; 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 &= PX_900_MASK;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1: // from: -- 390 --to--> z/Arch
|
|
|
|
if (sysblk.arch_mode == ARCH_900_IDX)
|
|
status = SIGP_STATUS_INVALID_PARAMETER;
|
|
else
|
|
{
|
|
sysblk.arch_mode = ARCH_900_IDX;
|
|
set_arch = 1;
|
|
|
|
INVALIDATE_AIA( regs );
|
|
regs->psw.states &= ~BIT( PSW_NOTESAME_BIT );
|
|
regs->psw.IA_H = 0;
|
|
regs->PX &= PX_900_MASK;
|
|
|
|
for (cpu = 0; cpu < sysblk.maxcpu; 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 &= PX_900_MASK;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2: // restore CAPTURED z/Arch PSW...
|
|
|
|
if (sysblk.arch_mode == ARCH_900_IDX)
|
|
status = SIGP_STATUS_INVALID_PARAMETER;
|
|
else
|
|
{
|
|
sysblk.arch_mode = ARCH_900_IDX;
|
|
set_arch = 1;
|
|
|
|
INVALIDATE_AIA( regs );
|
|
regs->psw.states &= ~BIT( PSW_NOTESAME_BIT );
|
|
regs->psw.IA_H = 0;
|
|
regs->PX &= PX_900_MASK;
|
|
|
|
for (cpu = 0; cpu < sysblk.maxcpu; 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 &= ARCH_900_IDX;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
#endif // defined( _900 ) || defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )
|
|
|
|
#if defined( FEATURE_HERCULES_DIAGCALLS )
|
|
|
|
case 37:
|
|
if (FACILITY_ENABLED( HERC_SIGP_SETARCH_S370, regs ))
|
|
{
|
|
if (sysblk.arch_mode == ARCH_370_IDX)
|
|
status = SIGP_STATUS_INVALID_PARAMETER;
|
|
else
|
|
{
|
|
sysblk.arch_mode = ARCH_370_IDX;
|
|
set_arch = 1;
|
|
}
|
|
}
|
|
else
|
|
status = SIGP_STATUS_INVALID_ORDER;
|
|
break;
|
|
|
|
#endif /* defined( FEATURE_HERCULES_DIAGCALLS ) */
|
|
|
|
default:
|
|
status |= SIGP_STATUS_INVALID_PARAMETER;
|
|
} /* end switch (parm & 0xFF) */
|
|
} /* end if (!status) */
|
|
|
|
sysblk.dummyregs.arch_mode = sysblk.arch_mode;
|
|
|
|
/* Invalidate the ALB and TLB */
|
|
ARCH_DEP( purge_tlb )( regs );
|
|
#if defined( FEATURE_ACCESS_REGISTERS )
|
|
ARCH_DEP( purge_alb )( tregs );
|
|
#endif
|
|
|
|
PERFORM_SERIALIZATION( regs );
|
|
PERFORM_CHKPT_SYNC( regs );
|
|
|
|
break;
|
|
#endif /*defined( _900 ) || defined( FEATURE_001_ZARCH_INSTALLED_FACILITY ) || defined( FEATURE_HERCULES_DIAGCALLS )*/
|
|
|
|
#if defined( FEATURE_009_SENSE_RUN_STATUS_FACILITY )
|
|
|
|
case SIGP_SENSE_RUNNING_STATE:
|
|
|
|
if (!FACILITY_ENABLED( 009_SENSE_RUN_STATUS, regs ))
|
|
status = SIGP_STATUS_INVALID_ORDER;
|
|
else if (tregs->cpustate != CPUSTATE_STARTED)
|
|
status = SIGP_STATUS_NOT_RUNNING;
|
|
|
|
break;
|
|
|
|
#endif /* defined( FEATURE_009_SENSE_RUN_STATUS_FACILITY ) */
|
|
|
|
default:
|
|
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)
|
|
PTT_ERR("*SIGP",parm,cpad,order);
|
|
|
|
/* 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)
|
|
{
|
|
if (regs->insttrace && sysblk.traceFILE)
|
|
tf_0814( regs, order, 0, cpad, status, parm, 0 );
|
|
else
|
|
// "Processor %s: CC %d%s"
|
|
WRMSG( HHC00814, "I", log_buf, 0, "" );
|
|
}
|
|
else
|
|
{
|
|
if (regs->insttrace && sysblk.traceFILE)
|
|
tf_0814( regs, order, regs->psw.cc, cpad, status, parm, 1 );
|
|
else
|
|
{
|
|
char buf[40];
|
|
MSGBUF( buf, " status %8.8X", (U32) status );
|
|
// "Processor %s: CC %d%s"
|
|
WRMSG( HHC00814, "I", log_buf, 1, buf );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Perform serialization after completing operation */
|
|
PERFORM_SERIALIZATION( regs );
|
|
|
|
#if defined( FEATURE_PER1 )
|
|
/* Check for PER 1 GRA event */
|
|
if (status != 0) // r1 modified?
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( r1 ));
|
|
#endif
|
|
|
|
#if defined( _900 ) || defined( FEATURE_001_ZARCH_INSTALLED_FACILITY ) || defined( FEATURE_HERCULES_DIAGCALLS )
|
|
if (set_arch)
|
|
{
|
|
OBTAIN_INTLOCK( regs );
|
|
longjmp( regs->archjmp, 0 );
|
|
}
|
|
#endif /*defined( _900 ) || defined( FEATURE_001_ZARCH_INSTALLED_FACILITY )*/
|
|
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
DW_CHECK( effective_addr2, regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC3, SCKC ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
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 (get_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 );
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, PSW_IA_FROM_IP( 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"PRIX64"\n", dreg );
|
|
|
|
RETURN_INTCHECK( regs );
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B6 STCTL - Store Control [RS-a] */
|
|
/*-------------------------------------------------------------------*/
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
#if defined( FEATURE_ECPSVM )
|
|
if (ecpsvm_dostctl( regs, r1, r3, b2, effective_addr2 ) == 0)
|
|
return;
|
|
#endif
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
FW_CHECK( effective_addr2, regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC1, STCTL ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* Calculate number of regs to store */
|
|
n = ((r3 - r1) & 0xF) + 1;
|
|
|
|
/* Calculate number of words to next boundary */
|
|
m = (PAGEFRAME_PAGESIZE - (effective_addr2 & PAGEFRAME_BYTEMASK)) >> 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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
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 */
|
|
|
|
S( inst, regs, b2, effective_addr2 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
SIE_INTERCEPT( regs );
|
|
|
|
DW_CHECK( effective_addr2, regs );
|
|
|
|
/* Store CPU ID at operand address */
|
|
ARCH_DEP( vstore8 )( regs->cpuid, 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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
DW_CHECK( effective_addr2, regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC3, SPT ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
OBTAIN_INTLOCK( regs );
|
|
{
|
|
/* Save the CPU timer value */
|
|
dreg = get_cpu_timer(regs);
|
|
|
|
/* reset the cpu timer pending flag according to its value */
|
|
if (unlikely( dreg < 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 );
|
|
SET_PSW_IA_AND_MAYBE_IP( regs, PSW_IA_FROM_IP( 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"PRIX64"\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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
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 real CPU capability indicator for the STSI instruction */
|
|
/* */
|
|
/* The CPU capability indicators are generated as two different, */
|
|
/* dynamically generated 32-bit values, based on the total MIPS per */
|
|
/* real CPU second: */
|
|
/* */
|
|
/* 1) An MSU value (straight-line generated, rather than assigned */
|
|
/* by a marketing group); this value is used for an ascending */
|
|
/* performance indicator. */
|
|
/* */
|
|
/* 2) A performance value with a lower value indicating 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, it is a */
|
|
/* 32-bit short BFP number. */
|
|
/* */
|
|
/* The generated values are stored in a static area, refreshed on */
|
|
/* type 111 calls, to keep consistency between data areas. */
|
|
/* */
|
|
/* */
|
|
/* Notes: */
|
|
/* */
|
|
/* 1) The real CPU capability indicators may fluctuate due to a */
|
|
/* variety of reasons during operation. */
|
|
/* */
|
|
/* 2) A real CPU second is defined to be time consumed in the host */
|
|
/* user state for a given thread. */
|
|
/* */
|
|
/* 3) Host kernel time is considered to be part of management and */
|
|
/* overhead times. */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
#if !defined( _STSI_CAPABILITY )
|
|
#define _STSI_CAPABILITY
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* MIPSreal - Gather and generate MIPS per real CPU second */
|
|
/*-------------------------------------------------------------------*/
|
|
long double MIPSreal()
|
|
{
|
|
U64 instcount = 0; /* Combined instruction count */
|
|
U64 cputime = 0; /* Combined CPU time in us */
|
|
int cpu; /* CPU loop variable */
|
|
long double result;
|
|
REGS* regs;
|
|
|
|
/* Gather real CPU time and instruction count for each processor.
|
|
* Since the real CPU time is managed by the clock, only the
|
|
* corresponding previous instruction counts are used.
|
|
*/
|
|
for (cpu = 0; cpu < sysblk.maxcpu; ++cpu)
|
|
{
|
|
/* Loop through online CP CPUs */
|
|
if (1
|
|
&& IS_CPU_ONLINE( cpu )
|
|
&& SCCB_PTYP_CP == sysblk.ptyp[ cpu ]
|
|
)
|
|
{
|
|
regs = sysblk.regs[ cpu ];
|
|
|
|
cputime += regs->rcputime;
|
|
instcount += regs->prevcount;
|
|
}
|
|
}
|
|
|
|
/* Calculate MIPS per real CPU second
|
|
*
|
|
* Dividing the total instruction count by the time in microseconds
|
|
* yields the average MIPS per real CPU second.
|
|
*/
|
|
result = (long double)instcount /
|
|
(long double)cputime;
|
|
|
|
return (result);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* stsi_capability - Generate capability matrix */
|
|
/*-------------------------------------------------------------------*/
|
|
enum
|
|
{
|
|
stsicap_refresh,
|
|
stsicap_read
|
|
} stsicap_request;
|
|
|
|
static void stsi_capability( const int stsicap_request )
|
|
{
|
|
/* The MSU and CPU factors used are estimates; actual MSUs assigned
|
|
* to the hardware are determined by exhaustive testing and vendor
|
|
* marketing requirements.
|
|
*/
|
|
static const long double CPU_Factor = 764748;
|
|
static const long double MSU_Factor_Multiplier =
|
|
9.99209649643744627640427E-1L;
|
|
|
|
static long double MSU_Factor;
|
|
static int Real_CPUs;
|
|
long double MIPS_cpu; /* MIPS per CPU */
|
|
|
|
/* If valid data and a read request, just return */
|
|
if (sysblk.cpmcap && stsicap_request == stsicap_read)
|
|
return;
|
|
|
|
/* Initialize current real CP CPU count; that is the lessor of the
|
|
* number of online CP engines plus reserved (possible CP) CPU
|
|
* count, or the number of host real logical processors.
|
|
*/
|
|
Real_CPUs = get_RealCPCount();
|
|
|
|
/* Create an MSU factor based on the number of possible CPs */
|
|
MSU_Factor = 0.125 * pow( MSU_Factor_Multiplier, MIN( Real_CPUs, 1 ) - 1 );
|
|
|
|
/* Request MIPS per real CPU second */
|
|
MIPS_cpu = MIPSreal();
|
|
|
|
/* Generate a rough MSU and CPU capabilities based on current MIPS
|
|
* per real CPU second, with a range of 1 - 2**23-1.
|
|
*/
|
|
sysblk.cpmcap = (U32)(CPU_Factor / MIPS_cpu) & 0x007FFFFFU;
|
|
|
|
if (!sysblk.cpmcap)
|
|
sysblk.cpmcap = 1;
|
|
|
|
sysblk.cpmcr = MIPS_cpu * Real_CPUs * MSU_Factor;
|
|
sysblk.cpncap = sysblk.cpmcap;
|
|
sysblk.cpccr = sysblk.cpcai = sysblk.cpncr = 0;
|
|
sysblk.cpmpcr = sysblk.cpmtcr = sysblk.cpmcr;
|
|
sysblk.cpnpcr = sysblk.cpntcr = sysblk.cpncr;
|
|
sysblk.cpscap = sysblk.cpmcap;
|
|
sysblk.cpacap = 0;
|
|
|
|
} /* end function stsi_capability */
|
|
#endif /*!defined( _STSI_CAPABILITY )*/
|
|
|
|
|
|
#if defined( 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 = 0; /* Mainstor address */
|
|
int i;
|
|
U16 offset; /* Offset into control block */
|
|
U32 curlvl; /* Current config level */
|
|
SYSIB111 *sysib111; /* Basic machine conf */
|
|
SYSIB121 *sysib121; /* Basic machine CPU */
|
|
SYSIB122 *sysib122; /* Basic machine CPUs */
|
|
SYSIB221 *sysib221; /* LPAR CPU */
|
|
SYSIB222 *sysib222; /* LPAR CPUs */
|
|
SYSIB322 *sysib322; /* VM CPUs */
|
|
SYSIBVMDB *sysibvmdb; /* VM description block */
|
|
|
|
#if defined( FEATURE_011_CONFIG_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_011_CONFIG_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 };
|
|
|
|
S( inst, regs, b2, effective_addr2 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
SIE_INTERCEPT( regs );
|
|
|
|
PTT_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_FROM_IP( regs,-4 ),
|
|
effective_addr2 );
|
|
#endif
|
|
|
|
/* Determine current configuration level */
|
|
#if defined( _FEATURE_EMULATE_VM )
|
|
if (FACILITY_ENABLED( HERC_VIRTUAL_MACHINE, regs ))
|
|
curlvl = STSI_GPR0_FC_VM;
|
|
else
|
|
#endif
|
|
#if defined( _FEATURE_HYPERVISOR )
|
|
if (FACILITY_ENABLED( HERC_LOGICAL_PARTITION, regs ))
|
|
curlvl = STSI_GPR0_FC_LPAR;
|
|
else
|
|
#endif
|
|
curlvl = STSI_GPR0_FC_BASIC;
|
|
|
|
/* Check function code */
|
|
if ((regs->GR_L( 0 ) & STSI_GPR0_FC_MASK) > curlvl)
|
|
{
|
|
#if defined( FEATURE_011_CONFIG_TOPOLOGY_FACILITY )
|
|
if (0
|
|
|| !FACILITY_ENABLED( 011_CONFIG_TOPOLOGY, regs )
|
|
|| (regs->GR_L( 0 ) & STSI_GPR0_FC_MASK) != STSI_GPR0_FC_CURRINFO
|
|
)
|
|
#endif
|
|
{
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
#if defined( DEBUG_STSI )
|
|
LOGMSG( "control.c: STSI cc=3 function code invalid\n" );
|
|
#endif
|
|
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 ) |= curlvl;
|
|
#if defined( DEBUG_STSI )
|
|
LOGMSG( "control.c: STSI cc=0 R0=%8.8X\n", regs->GR_L( 0 ) );
|
|
#endif
|
|
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 */
|
|
{
|
|
U32 fcod = (regs->GR_L( 0 ) & STSI_GPR0_FC_MASK);
|
|
U32 sel1 = (regs->GR_L( 0 ) & STSI_GPR0_SEL1_MASK);
|
|
U32 sel2 = (regs->GR_L( 1 ) & STSI_GPR1_SEL2_MASK);
|
|
|
|
/*
|
|
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
|
|
15 1 3 (not currently supported) (TODO!)
|
|
15 1 4 (not currently supported) (TODO!)
|
|
15 1 5 (not currently supported) (TODO!)
|
|
15 1 6 (not currently supported) (TODO!)
|
|
*/
|
|
if (0
|
|
|| (STSI_GPR0_FC_BASIC == fcod
|
|
&& (0
|
|
|| sel1 == 0
|
|
|| sel1 > 2
|
|
|| sel2 == 0
|
|
|| sel2 > 2
|
|
)
|
|
)
|
|
#if defined( _FEATURE_HYPERVISOR )
|
|
|| (STSI_GPR0_FC_LPAR == fcod
|
|
&& (0
|
|
|| !FACILITY_ENABLED( HERC_LOGICAL_PARTITION, regs )
|
|
|| !sysblk.lparmode
|
|
|| sel1 != 2
|
|
|| sel2 == 0
|
|
|| sel2 > 2
|
|
)
|
|
)
|
|
#endif
|
|
#if defined( _FEATURE_EMULATE_VM )
|
|
|| (STSI_GPR0_FC_VM == fcod
|
|
&& (0
|
|
|| sel1 != 2
|
|
|| sel2 != 2
|
|
)
|
|
)
|
|
#endif
|
|
#if defined( FEATURE_011_CONFIG_TOPOLOGY_FACILITY )
|
|
|| (STSI_GPR0_FC_CURRINFO == fcod
|
|
&& (0
|
|
|| !FACILITY_ENABLED( 011_CONFIG_TOPOLOGY, regs )
|
|
|| sel1 != 1
|
|
#if 1 // (the only selector 2 value we currently support)
|
|
|| sel2 != 2
|
|
#else // (TODO: provide support for selectors 3-6)
|
|
|| sel2 < 2
|
|
|| sel2 > 6
|
|
#endif
|
|
)
|
|
)
|
|
#endif
|
|
)
|
|
{
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
#if defined( DEBUG_STSI )
|
|
LOGMSG( "control.c: STSI cc=3 selector codes invalid\n" );
|
|
#endif
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (regs->GR_L( 0 ) & STSI_GPR0_FC_MASK) {
|
|
|
|
case STSI_GPR0_FC_BASIC:
|
|
|
|
/* 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_SEL1_MASK) {
|
|
|
|
case 1:
|
|
|
|
switch (regs->GR_L( 1 ) & STSI_GPR1_SEL2_MASK) {
|
|
|
|
case 1:
|
|
/* Basic-machine configuration */
|
|
sysib111 = (SYSIB111*)(m);
|
|
memset( sysib111, 0, MAX( sizeof(SYSIB111), 64*4 ));
|
|
stsi_capability( stsicap_refresh );
|
|
sysib111->flag1 |= SYSIB111_PFLAG;
|
|
get_manufacturer( sysib111->manufact );
|
|
get_model( sysib111->model );
|
|
for (i=0; i < 4; i++)
|
|
sysib111->type[i] =
|
|
hexebcdic[(sysblk.cpumodel >> (12 - (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 );
|
|
bld_sysib_sequence( sysib111->seqc );
|
|
get_plant( sysib111->plant );
|
|
STORE_FW( sysib111->mcaprating, sysblk.cpmcr );
|
|
STORE_FW( sysib111->mpcaprating, sysblk.cpmpcr );
|
|
STORE_FW( sysib111->mtcaprating, sysblk.cpmtcr );
|
|
for (i=0; i < 5; i++)
|
|
{
|
|
sysib111->typepct[i] = 100;
|
|
}
|
|
if (sysblk.cpcai)
|
|
{
|
|
sysib111->ccr = 1;
|
|
sysib111->cai = sysblk.cpcai;
|
|
STORE_FW( sysib111->ncaprating, sysblk.cpncr );
|
|
STORE_FW( sysib111->npcaprating, sysblk.cpnpcr );
|
|
STORE_FW( sysib111->ntcaprating, sysblk.cpntcr );
|
|
}
|
|
regs->psw.cc = 0;
|
|
break;
|
|
|
|
default:
|
|
PTT_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, 0, MAX( sizeof( SYSIB121 ), 64*4 ));
|
|
bld_sysib_sequence( sysib121->seqc );
|
|
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, 0, MAX( sizeof( SYSIB122 ), 64*4 ));
|
|
stsi_capability( stsicap_read );
|
|
if (0) /* Change -0- to the proper test when Hercules supports alternate CPUs */
|
|
{
|
|
sysib122->format = 1;
|
|
offset = (U16)(sysib122->accap - (BYTE*)sysib122);
|
|
STORE_HW( sysib122->accoff, offset );
|
|
}
|
|
STORE_FW( sysib122->nccap, sysblk.cpncap );
|
|
STORE_FW( sysib122->sccap, sysblk.cpscap );
|
|
STORE_FW( sysib122->cap, sysblk.cpmcap );
|
|
STORE_HW( sysib122->totcpu, MAX_CPU_ENGS );
|
|
STORE_HW( sysib122->confcpu, sysblk.cpus );
|
|
STORE_HW( sysib122->sbcpu, sysblk.maxcpu - sysblk.cpus );
|
|
STORE_HW( sysib122->resvcpu, MAX_CPU_ENGS - sysblk.maxcpu );
|
|
get_mpfactors( (BYTE*)sysib122->mpfact );
|
|
if (sysib122->format)
|
|
{
|
|
STORE_FW( sysib122->accap, sysblk.cpacap );
|
|
get_mpfactors( (BYTE*)sysib122->ampfact );
|
|
}
|
|
regs->psw.cc = 0;
|
|
break;
|
|
|
|
default:
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
regs->psw.cc = 3;
|
|
} /* selector 2 */
|
|
break;
|
|
|
|
default:
|
|
PTT_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:
|
|
|
|
#if defined( _FEATURE_HYPERVISOR )
|
|
if (!FACILITY_ENABLED( HERC_LOGICAL_PARTITION, regs ))
|
|
{
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
regs->psw.cc = 3;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
/* 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_SEL1_MASK) {
|
|
|
|
case 2:
|
|
|
|
switch (regs->GR_L( 1 ) & STSI_GPR1_SEL2_MASK) {
|
|
|
|
case 1:
|
|
/* Logical-partition Current CPU */
|
|
sysib221 = (SYSIB221 *)(m);
|
|
memset( sysib221, 0, MAX( sizeof( SYSIB221 ), 64*4 ));
|
|
bld_sysib_sequence( sysib221->seqc );
|
|
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, 0, MAX( sizeof( SYSIB222 ), 64*4 ));
|
|
STORE_HW( sysib222->lparnum, sysblk.lparnum );
|
|
sysib222->lcpuc = SYSIB222_LCPUC_SHARED;
|
|
STORE_HW( sysib222->totcpu, MAX_CPU_ENGS );
|
|
STORE_HW( sysib222->confcpu, sysblk.cpus );
|
|
STORE_HW( sysib222->sbcpu, sysblk.maxcpu - sysblk.cpus );
|
|
STORE_HW( sysib222->resvcpu, MAX_CPU_ENGS - sysblk.maxcpu );
|
|
get_lparname(sysib222->lparname);
|
|
/* FIXME: Should be a percentage of 1000, where 1000
|
|
* represents 1.000 and capable of full CPU
|
|
* utilization. This usually is NOT the case for
|
|
* an LPAR, by definition.
|
|
*/
|
|
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_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
regs->psw.cc = 3;
|
|
} /* selector 2 */
|
|
break;
|
|
|
|
default:
|
|
PTT_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_VM:
|
|
|
|
/* 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 );
|
|
|
|
sysib322 = (SYSIB322 *)(m);
|
|
memset( sysib322, 0, sizeof( SYSIB322 ));
|
|
sysib322->dbct = 1;
|
|
sysibvmdb = (SYSIBVMDB *)&sysib322->vmdb[0];
|
|
STORE_HW( sysibvmdb->totcpu, MAX_CPU_ENGS );
|
|
STORE_HW( sysibvmdb->confcpu, sysblk.cpus );
|
|
STORE_HW( sysibvmdb->sbcpu, sysblk.maxcpu - sysblk.cpus );
|
|
STORE_HW( sysibvmdb->resvcpu, MAX_CPU_ENGS - sysblk.maxcpu );
|
|
get_vmid( sysibvmdb->vmname );
|
|
STORE_FW( sysibvmdb->vmcaf, 1000 ); /* Full capability factor */
|
|
get_cpid( sysibvmdb->cpid );
|
|
|
|
regs->psw.cc = 0;
|
|
break;
|
|
|
|
#if defined( FEATURE_011_CONFIG_TOPOLOGY_FACILITY )
|
|
case STSI_GPR0_FC_CURRINFO:
|
|
|
|
if (!FACILITY_ENABLED( 011_CONFIG_TOPOLOGY, regs ))
|
|
{
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
regs->psw.cc = 3;
|
|
break;
|
|
}
|
|
|
|
/* 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_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, 0, sizeof( SYSIB1512 ));
|
|
|
|
sysib1512->mnest = 2;
|
|
sysib1512->mag[4] = 1;
|
|
sysib1512->mag[5] = sysblk.maxcpu;
|
|
|
|
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 <= MAX_SCCB_PTYP; 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, 0, 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;
|
|
|
|
case 3: // TODO...
|
|
case 4: // TODO...
|
|
case 5: // TODO...
|
|
case 6: // TODO...
|
|
|
|
default:
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
regs->psw.cc = 3;
|
|
} /* selector 2 */
|
|
break;
|
|
|
|
default:
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
regs->psw.cc = 3;
|
|
} /* selector 1 */
|
|
break;
|
|
#endif /* defined( FEATURE_011_CONFIG_TOPOLOGY_FACILITY ) */
|
|
|
|
default:
|
|
PTT_ERR("*STSI",regs->GR_L( 0 ),regs->GR_L( 1 ),(U32)(effective_addr2 & 0xffffffff));
|
|
regs->psw.cc = 3;
|
|
} /* function code */
|
|
|
|
#if defined( 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((unsigned char)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 /* defined( DEBUG_STSI ) */
|
|
|
|
} /* end DEF_INST(store_system_information) */
|
|
#endif /* defined( FEATURE_STORE_SYSTEM_INFORMATION ) */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* AC STNSM - Store Then And System 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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b1 );
|
|
|
|
#if defined( FEATURE_ECPSVM )
|
|
if (ecpsvm_dostnsm( regs, b1, effective_addr1, i2 ) == 0)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC1, STNSM ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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 );
|
|
|
|
#if defined( FEATURE_002_ZARCH_ACTIVE_FACILITY )
|
|
if ((effective_addr1 == 0x00000950) && (i2 == 0xff))
|
|
{
|
|
if (!ARCH_DEP( translate_addr )( 16, 0, regs, ACCTYPE_READ ))
|
|
{
|
|
VADR va_1 = ARCH_DEP( vfetch4 )( 16, 0, regs ) + 140;
|
|
if (!ARCH_DEP( translate_addr )( va_1, 0, regs, ACCTYPE_READ ))
|
|
{
|
|
VADR va_2 = ARCH_DEP( vfetch4 )( va_1, 0, regs ) + 476;
|
|
if (!ARCH_DEP( translate_addr )( va_2, 0, regs, ACCTYPE_READ ))
|
|
{
|
|
if (ARCH_DEP( vfetch2 )( va_2, 0, regs ) >= 258)
|
|
ARCH_DEP( vstoreb )( 0x00, 1376 + ARCH_DEP( vfetch4 )( 2892, 0, regs ), 0, regs );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
RETURN_INTCHECK( regs );
|
|
} /* end DEF_INST(store_then_and_system_mask) */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* AD STOSM - Store Then Or System 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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b1 );
|
|
|
|
#if defined( FEATURE_ECPSVM )
|
|
if (ecpsvm_dostosm( regs, b1, effective_addr1, i2 ) == 0)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC1, STOSM ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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 (1
|
|
&& SIE_STATE_BIT_ON( regs, MX, XC )
|
|
&& (regs->psw.sysmask & PSW_DATMODE)
|
|
)
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
#endif
|
|
|
|
/* 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 );
|
|
|
|
PER_ZEROADDR_CHECK( regs, r2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
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 (1
|
|
&& EN_IC_PER_SA( regs ) && !IS_PER_SUPRESS( regs, CR9_SA )
|
|
&& EN_IC_PER_STURA( regs ) && !IS_PER_SUPRESS( regs, CR9_STURA )
|
|
)
|
|
{
|
|
ON_IC_PER_SA( regs );
|
|
ON_IC_PER_STURA( regs );
|
|
regs->perc &= 0xFFFC; /* zero STD ID part of PER code */
|
|
}
|
|
#endif
|
|
} /* 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 );
|
|
|
|
/* All control instructions are restricted in transaction mode */
|
|
TXF_INSTR_CHECK( regs );
|
|
|
|
/* 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_STATE_BIT_ON( regs, MX, XC ) ? HOSTREGS :
|
|
#endif
|
|
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 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
#if defined( FEATURE_REGION_RELOCATE )
|
|
if (SIE_STATE_BIT_OFF( 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( 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 ))
|
|
{
|
|
#if defined( FEATURE_SUPPRESSION_ON_PROTECTION )
|
|
regs->TEA = (n & STORAGE_KEY_PAGEMASK);
|
|
regs->excarid = 0;
|
|
#endif
|
|
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 */
|
|
clear_page_4K( regs->mainstor + n );
|
|
|
|
/* Set condition code 0 if storage usable, 1 if unusable.
|
|
Note: we use the internal "_get_storage_key" function
|
|
so we're returned the internal STORKEY_BADFRM bit too.
|
|
*/
|
|
if (ARCH_DEP( _get_storage_key )( n, SKEY_K ) & STORKEY_BADFRM)
|
|
regs->psw.cc = 1;
|
|
else
|
|
regs->psw.cc = 0;
|
|
}
|
|
PERFORM_SERIALIZATION( regs );
|
|
|
|
/* Clear general register 0 */
|
|
SET_GR_A( 0, regs, 0 );
|
|
|
|
/* Check for PER 1 GRA event */
|
|
PER_GRA_CHECK( regs, PER_GRA_MASK( 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 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
PRIV_CHECK( regs );
|
|
|
|
#if defined( _FEATURE_SIE )
|
|
if (SIE_STATE_BIT_ON( regs, IC2, TPROT ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
#endif
|
|
|
|
/* 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,
|
|
HOSTREGS, ACCTYPE_SIE ))
|
|
longjmp( regs->progjmp, SIE_INTERCEPT_INST );
|
|
|
|
/* Convert host real address to host absolute address */
|
|
aaddr = apply_host_prefixing( HOSTREGS, HOSTREGS->dat.raddr );
|
|
|
|
if (aaddr > 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 = ARCH_DEP( get_storage_key )( aaddr );
|
|
|
|
/* 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-a] */
|
|
/*-------------------------------------------------------------------*/
|
|
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 );
|
|
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
TXF_INSTR_CHECK( regs );
|
|
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( _ARCH_NUM_1 )
|
|
#define _GEN_ARCH _ARCH_NUM_1
|
|
#include "control.c"
|
|
#endif
|
|
|
|
#if defined( _ARCH_NUM_2 )
|
|
#undef _GEN_ARCH
|
|
#define _GEN_ARCH _ARCH_NUM_2
|
|
#include "control.c"
|
|
#endif
|
|
|
|
#endif /*!defined( _GEN_ARCH )*/
|