Files
org-hyperion-cules/control.c
Jay Maynard 6c2c7f225a Portability fixes (Alphas and 128-bit long longs don't mix!).
git-svn-id: file:///home/jj/hercules.svn/trunk@832 956126f8-22a0-4046-8f4a-272fa8102e63
2002-04-19 16:35:11 +00:00

5930 lines
206 KiB
C

/* CONTROL.C (c) Copyright Roger Bowler, 1994-2002 */
/* ESA/390 CPU Emulator */
/* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2002 */
/* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2002 */
/*-------------------------------------------------------------------*/
/* 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*/
/*-------------------------------------------------------------------*/
#include "hercules.h"
#include "opcode.h"
#include "inline.h"
#if defined(OPTION_FISHIO)
#include "w32chan.h"
#endif // defined(OPTION_FISHIO)
#if defined(FEATURE_BRANCH_AND_SET_AUTHORITY)
/*-------------------------------------------------------------------*/
/* B25A BSA - Branch and Set Authority [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(branch_and_set_authority)
{
int r1, r2; /* Values of R fields */
U32 ducto; /* DUCT origin */
U32 duct_pkrp; /* DUCT PKM/Key/RA/P word */
RADR duct_reta; /* DUCT return address/amode */
BYTE key; /* New PSW key */
#ifdef FEATURE_TRACING
CREG newcr12 = 0; /* CR12 upon completion */
#endif /*FEATURE_TRACING*/
RRE(inst, execflag, regs, r1, r2);
/* Special operation exception if ASF is not enabled */
if (!ASF_ENABLED(regs))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_BSA))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Load real address of dispatchable unit control table */
ducto = regs->CR(2) & CR2_DUCTO;
/* Apply low-address protection to stores into the DUCT */
if (ARCH_DEP(is_low_address_protected) (ducto, 0, regs))
{
#ifdef FEATURE_SUPPRESSION_ON_PROTECTION
regs->TEA = (ducto & STORAGE_KEY_PAGEMASK);
regs->excarid = 0;
#endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/
ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION);
}
/* Convert DUCT real address to absolute address */
ducto = APPLY_PREFIXING (ducto, regs->PX);
/* Program check if DUCT origin address is invalid */
if (ducto >= regs->mainsize)
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(FEATURE_ESAME)
/* For ESAME, load the PKM/Key/RA/P from DUCT word 5, and load
the return address and amode from DUCT words 8 and 9
(note: the DUCT cannot cross a page boundary) */
duct_pkrp = ARCH_DEP(fetch_fullword_absolute) (ducto+20, regs);
duct_reta = ARCH_DEP(fetch_doubleword_absolute) (ducto+32, regs);
#else /*!defined(FEATURE_ESAME)*/
/* For ESA/390, load the PKM/Key/RA/P from DUCT word 9, and load
the return address and amode from DUCT word 8
(note: the DUCT cannot cross a page boundary) */
duct_pkrp = ARCH_DEP(fetch_fullword_absolute) (ducto+36, regs);
duct_reta = ARCH_DEP(fetch_fullword_absolute) (ducto+32, regs);
#endif /*!defined(FEATURE_ESAME)*/
/* Perform base authority or reduced authority operation */
if ((duct_pkrp & DUCT_RA) == 0)
{
/* In base authority state R2 cannot specify register zero */
if (r2 == 0)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#ifdef FEATURE_TRACING
/* Perform tracing */
if (regs->CR(12) & CR12_BRTRACE)
newcr12 = ARCH_DEP(trace_br) (regs->GR_L(r2) & 0x80000000,
regs->GR_L(r2), regs);
#endif /*FEATURE_TRACING*/
/* Obtain the new PSW key from R1 register bits 24-27 */
key = regs->GR_L(r1) & 0x000000F0;
/* Privileged operation exception if in problem state and
current PSW key mask does not permit new key value */
if (regs->psw.prob
&& ((regs->CR(3) << (key >> 4)) & 0x80000000) == 0 )
ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
/* Save current PSW amode and instruction address */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
{
duct_reta = regs->psw.IA;
}
else
#endif /*!defined(FEATURE_ESAME)*/
{
duct_reta = regs->psw.IA & 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 (regs->psw.prob) duct_pkrp |= DUCT_PROB;
/* Set the reduced authority bit */
duct_pkrp |= DUCT_RA;
#if defined(FEATURE_ESAME)
/* For ESAME, store the PKM/Key/RA/P into DUCT word 5, and
store the return address and amode into DUCT words 8 and 9
(note: the DUCT cannot cross a page boundary) */
ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+20, regs);
ARCH_DEP(store_doubleword_absolute) (duct_reta, ducto+32, regs);
#else /*!defined(FEATURE_ESAME)*/
/* For ESA/390, store the PKM/Key/RA/P into DUCT word 9, and
store the return address and amode into DUCT word 8
(note: the DUCT cannot cross a page boundary) */
ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+36, regs);
ARCH_DEP(store_fullword_absolute) (duct_reta, ducto+32, regs);
#endif /*!defined(FEATURE_ESAME)*/
/* Load new PSW key and PSW key mask from R1 register */
regs->psw.pkey = key;
regs->CR_LHH(3) &= regs->GR_LHH(r1);
/* Set the problem state bit in the current PSW */
regs->psw.prob = 1;
/* Set PSW instruction address and amode from R2 register */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
{
regs->psw.IA = regs->GR_G(r2);
}
else
#endif /*defined(FEATURE_ESAME)*/
if (regs->GR_L(r2) & 0x80000000)
{
#if defined(FEATURE_ESAME)
regs->psw.amode64 = 0;
#endif /*defined(FEATURE_ESAME)*/
regs->psw.amode = 1;
regs->psw.AMASK = AMASK31;
regs->psw.IA = regs->GR_L(r2) & AMASK31;
}
else
{
#if defined(FEATURE_ESAME)
regs->psw.amode64 =
#endif /*defined(FEATURE_ESAME)*/
regs->psw.amode = 0;
regs->psw.AMASK = AMASK24;
regs->psw.IA = regs->GR_L(r2) & AMASK24;
}
} /* end if(BSA-ba) */
else
{ /* BSA-ra */
/* In reduced authority state R2 must specify register zero */
if (r2 != 0)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#ifdef FEATURE_TRACING
/* Perform tracing */
if (regs->CR(12) & CR12_BRTRACE)
newcr12 = ARCH_DEP(trace_br) (duct_reta & DUCT_AM31,
duct_reta &DUCT_IA31, regs);
#endif /*FEATURE_TRACING*/
/* If R1 is non-zero, save the current PSW addressing mode
and instruction address in the R1 register */
if (r1 != 0)
{
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
{
regs->GR_G(r1) = regs->psw.IA;
}
else
#endif /*defined(FEATURE_ESAME)*/
{
regs->GR_L(r1) = regs->psw.IA;
if (regs->psw.amode) regs->GR_L(r1) |= 0x80000000;
}
}
/* Restore PSW amode and instruction address from the DUCT */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
{
regs->psw.IA = duct_reta;
}
else
#endif /*defined(FEATURE_ESAME)*/
{
regs->psw.IA = duct_reta & DUCT_IA31;
regs->psw.amode = (duct_reta & DUCT_AM31) ? 1 : 0;
regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24;
}
/* Restore the PSW key mask from the DUCT */
regs->CR(3) &= 0x0000FFFF;
regs->CR(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 */
regs->psw.prob = (duct_pkrp & DUCT_PROB) ? 1 : 0;
/* Reset the reduced authority bit in the DUCT */
duct_pkrp &= ~DUCT_RA;
#if defined(FEATURE_ESAME)
ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+20, regs);
#else /*!defined(FEATURE_ESAME)*/
ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+36, regs);
#endif /*!defined(FEATURE_ESAME)*/
/* Specification exception if the PSW is now invalid */
if ((regs->psw.IA & 1)
#if defined(FEATURE_ESAME)
|| (regs->psw.amode64 == 0 && regs->psw.amode == 1
&& regs->psw.IA > 0x7FFFFFFF)
|| (regs->psw.amode64 == 0 && regs->psw.amode == 0
&& regs->psw.IA > 0x00FFFFFF))
#else /*!defined(FEATURE_ESAME)*/
|| (regs->psw.amode == 0 && regs->psw.IA > 0x00FFFFFF))
#endif /*!defined(FEATURE_ESAME)*/
{
regs->psw.ilc = 0;
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
}
} /* end if(BSA-ra) */
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
#ifdef FEATURE_TRACING
/* Update trace table address if branch tracing is on */
if (regs->CR(12) & CR12_BRTRACE)
regs->CR(12) = newcr12;
#endif /*FEATURE_TRACING*/
#if defined(FEATURE_PER)
if( EN_IC_PER_SB(regs)
#if defined(FEATURE_PER2)
&& ( !(regs->CR(9) & CR9_BAC)
|| PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) )
#endif /*defined(FEATURE_PER2)*/
)
ON_IC_PER_SB(regs);
#endif /*defined(FEATURE_PER)*/
}
#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; /* 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 */
VADR newia; /* New instruction address */
int protect = 0; /* 1=ALE protection detected
by ART (ignored by BSG) */
U16 xcode; /* Exception code */
#ifdef FEATURE_TRACING
CREG newcr12 = 0; /* CR12 upon completion */
#endif /*FEATURE_TRACING*/
RRE(inst, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(regs);
/* Special operation exception if DAT is off or ASF not enabled */
if (REAL_MODE(&(regs->psw))
|| !ASF_ENABLED(regs))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#ifdef FEATURE_TRACING
/* Perform tracing */
if (regs->CR(12) & CR12_ASNTRACE)
newcr12 = ARCH_DEP(trace_bsg) ((r2 == 0) ? 0 : regs->AR(r2),
regs->GR_L(r2), regs);
else
if (regs->CR(12) & CR12_BRTRACE)
newcr12 = ARCH_DEP(trace_br) (regs->GR_L(r2) & 0x80000000,
regs->GR_L(r2), regs);
#endif /*FEATURE_TRACING*/
/* Load real address of dispatchable unit control table */
ducto = regs->CR(2) & CR2_DUCTO;
/* Apply low-address protection to stores into the DUCT */
if (ARCH_DEP(is_low_address_protected) (ducto, 0, regs))
{
#ifdef FEATURE_SUPPRESSION_ON_PROTECTION
regs->TEA = (ducto & STORAGE_KEY_PAGEMASK);
regs->excarid = 0;
#endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/
ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION);
}
/* Convert DUCT real address to absolute address */
ducto = APPLY_PREFIXING (ducto, regs->PX);
/* Program check if DUCT origin address is invalid */
if (ducto >= regs->mainsize)
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) */
duct0 = ARCH_DEP(fetch_fullword_absolute) (ducto, regs);
duct1 = ARCH_DEP(fetch_fullword_absolute) (ducto+4, regs);
duct3 = ARCH_DEP(fetch_fullword_absolute) (ducto+12, regs);
/* 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->mainsize)
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) */
daste[2] = ARCH_DEP(fetch_fullword_absolute) (abs+8, regs);
daste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs);
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->mainsize)
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) */
daste[0] = ARCH_DEP(fetch_fullword_absolute) (abs, regs);
daste[2] = ARCH_DEP(fetch_fullword_absolute) (abs+8, regs);
daste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs);
daste[5] = ARCH_DEP(fetch_fullword_absolute) (abs+20, regs);
/* 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, &protect);
/* Program check if ALET translation error */
if (xcode != 0)
{
regs->excarid = r2;
ARCH_DEP(program_interrupt) (regs, xcode);
}
/* Special operation exception if the destination ASTE
is the base space of a different subspace group */
if (dasteo != (duct0 & DUCT0_BASTEO)
&& ((ASTE_AS_DESIGNATOR(daste) & SSGROUP_BIT) == 0
|| (daste[0] & ASTE0_BASE) ))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
} /* end switch(alet) */
/* Update the primary STD (or ASCE) from the destination ASTE */
if ((dasteo == (duct0 & DUCT0_BASTEO)) && (alet != ALET_SECONDARY))
{
/* When the destination ASTE is the base space, replace the
primary STD (or ASCE) by the STD (or ASCE) in the ASTE */
regs->CR(1) = ASTE_AS_DESIGNATOR(daste);
}
else
{
/* When the destination ASTE is a subspace, replace
the primary STD or ASCE by the STD or ASTE in the
ASTE, except for the space-switch event and storage
alteration event bits, which remain unchanged */
regs->CR(1) &= (SSEVENT_BIT | SAEVENT_BIT);
regs->CR(1) |= (ASTE_AS_DESIGNATOR(daste)
& ~((RADR)(SSEVENT_BIT | SAEVENT_BIT)));
}
/* Compute the branch address from the R2 operand */
newia = regs->GR(r2);
/* If R1 is non-zero, save the current PSW addressing mode
and instruction address in the R1 register */
if (r1 != 0)
{
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
regs->GR_G(r1) = regs->psw.IA;
else
#endif /*!defined(FEATURE_ESAME)*/
regs->GR_L(r1) = regs->psw.IA |
(regs->psw.amode ? 0x80000000 : 0);
}
/* Set mode and branch to address specified by R2 operand */
regs->psw.IA = newia;
#if defined(FEATURE_ESAME)
if (regs->psw.amode64 == 0 && (newia & 0x80000000))
#else /*!defined(FEATURE_ESAME)*/
if (newia & 0x80000000)
#endif /*!defined(FEATURE_ESAME)*/
{
regs->psw.amode = 1;
regs->psw.AMASK = AMASK31;
regs->psw.IA = newia & AMASK31;
}
else
{
regs->psw.amode = 0;
regs->psw.AMASK = AMASK24;
regs->psw.IA = newia & AMASK24;
}
/* 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);
/* Reset the subspace fields in the DUCT */
if (alet == ALET_SECONDARY)
{
/* When the destination ASTE specifies a subspace by means
of ALET 1, set the subspace active bit in the DUCT */
duct1 |= DUCT1_SA;
ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs);
}
else if (dasteo == (duct0 & DUCT0_BASTEO))
{
/* When the destination ASTE is the base space,
reset the subspace active bit in the DUCT */
duct1 &= ~DUCT1_SA;
ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs);
}
else
{
/* When the destination ASTE specifies a subspace by means
of an ALET other than ALET 1, set the subspace active
bit and store the subspace ASTE origin in the DUCT */
duct1 = DUCT1_SA | dasteo;
ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs);
/* Set the subspace ASTE sequence number in the DUCT
equal to the destination ASTE sequence number */
duct3 = daste[5];
ARCH_DEP(store_fullword_absolute) (duct3, ducto+12, regs);
}
#ifdef FEATURE_TRACING
/* Update trace table address if ASN tracing or branch tracing */
if (regs->CR(12) & (CR12_ASNTRACE | CR12_BRTRACE))
regs->CR(12) = newcr12;
#endif /*FEATURE_TRACING*/
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
#if defined(FEATURE_PER)
if( EN_IC_PER_SB(regs)
#if defined(FEATURE_PER2)
&& ( !(regs->CR(9) & CR9_BAC)
|| PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) )
#endif /*defined(FEATURE_PER2)*/
)
ON_IC_PER_SB(regs);
#endif /*defined(FEATURE_PER)*/
}
#endif /*defined(FEATURE_SUBSPACE_GROUP)*/
#if defined(FEATURE_LINKAGE_STACK)
/*-------------------------------------------------------------------*/
/* B240 BAKR - Branch and Stack Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(branch_and_stack)
{
int r1, r2; /* Values of R fields */
VADR n1, n2; /* Operand values */
#ifdef FEATURE_TRACING
VADR n = 0; /* Work area */
#endif /*FEATURE_TRACING*/
RRE(inst, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_BAKR))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* [5.12.3]/ Fig 10-2 Special operation exception if ASF is not enabled,
or if DAT is off, or if not primary-space mode or AR-mode */
if (!ASF_ENABLED(regs)
|| REAL_MODE(&regs->psw)
|| regs->psw.space == 1)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Obtain the return address and addressing mode from
the R1 register, or use updated PSW if R1 is zero */
if ( r1 != 0 )
{
n1 = regs->GR(r1);
#if defined(FEATURE_ESAME)
if ( (n1 & 0x01) == 0 )
n1 &= (n1 & 0x80000000) ? 0xFFFFFFFF : 0x00FFFFFF;
#else /*!defined(FEATURE_ESAME)*/
if ( (n1 & 0x80000000) == 0 )
n1 &= 0x00FFFFFF;
#endif /*!defined(FEATURE_ESAME)*/
}
else
{
n1 = regs->psw.IA;
#if defined(FEATURE_ESAME)
if ( regs->psw.amode64 )
n1 |= 0x01;
else
#endif /*defined(FEATURE_ESAME)*/
if ( regs->psw.amode )
n1 |= 0x80000000;
}
/* Obtain the branch address from the R2 register, or use
the updated PSW instruction address if R2 is zero */
n2 = (r2 != 0) ? regs->GR(r2) : regs->psw.IA;
n2 &= ADDRESS_MAXWRAP(regs);
/* Set the addressing mode bit in the branch address */
#if defined(FEATURE_ESAME)
if ( regs->psw.amode64 )
n2 |= 0x01;
else
#endif /*defined(FEATURE_ESAME)*/
if ( regs->psw.amode )
n2 |= 0x80000000;
#ifdef FEATURE_TRACING
/* Form the branch trace entry */
if((regs->CR(12) & CR12_BRTRACE) && (r2 != 0))
n = ARCH_DEP(trace_br)(regs->psw.amode, regs->GR_L(r2), regs);
#endif /*FEATURE_TRACING*/
/* Form the linkage stack entry */
ARCH_DEP(form_stack_entry) (LSED_UET_BAKR, n1, n2, 0, 0, regs);
#ifdef FEATURE_TRACING
/* Update CR12 to reflect the new branch trace entry */
if((regs->CR(12) & CR12_BRTRACE) && (r2 != 0))
regs->CR(12) = n;
#endif /*FEATURE_TRACING*/
/* Execute the branch unless R2 specifies register 0 */
if ( r2 != 0 )
{
regs->psw.IA = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
#if defined(FEATURE_PER)
if( EN_IC_PER_SB(regs)
#if defined(FEATURE_PER2)
&& ( !(regs->CR(9) & CR9_BAC)
|| PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) )
#endif /*defined(FEATURE_PER2)*/
)
ON_IC_PER_SB(regs);
#endif /*defined(FEATURE_PER)*/
}
}
#endif /*defined(FEATURE_LINKAGE_STACK)*/
#if defined(FEATURE_BROADCASTED_PURGING)
/*-------------------------------------------------------------------*/
/* B250 CSP - Compare and Swap and Purge [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(compare_and_swap_and_purge)
{
int r1, r2; /* Values of R fields */
U32 n1, n2; /* 32 Bit work */
RADR abs2; /* absolute address of op2 */
RRE(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
ODD_CHECK(r1, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[0] & SIE_IC0_IPTECSP))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
#if defined(_FEATURE_SIE)
if(regs->sie_state && regs->sie_scao)
{
STORAGE_KEY(regs->sie_scao) |= STORKEY_REF;
if(sysblk.mainstor[regs->sie_scao] & 0x80)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
}
#endif /*defined(_FEATURE_SIE)*/
/* Perform serialization before starting operation */
PERFORM_SERIALIZATION (regs);
/* Obtain main-storage access lock */
OBTAIN_MAINLOCK(regs);
/* Obtain 2nd operand address from r2 */
n2 = regs->GR(r2) & 0xFFFFFFFFFFFFFFFCULL & ADDRESS_MAXWRAP(regs);
abs2 = LOGICAL_TO_ABS (n2, r2, regs, ACCTYPE_WRITE, regs->psw.pkey);
/* Load second operand from operand address */
n1 = fetch_fw(sysblk.mainstor + abs2);
/* Compare operand with R1 register contents */
if ( regs->GR_L(r1) == n1 )
{
/* If equal, store R1+1 at operand location and set cc=0 */
STORE_FW(sysblk.mainstor + abs2, regs->GR_L(r1+1));
regs->psw.cc = 0;
/* Release main-storage access lock */
RELEASE_MAINLOCK(regs);
/* Perform requested funtion specified as per request code in r2 */
if (regs->GR_L(r2) & 3)
ARCH_DEP(synchronize_broadcast)(regs, regs->GR_L(r2) & 3, 0);
}
else
{
/* If unequal, load R1 from operand and set cc=1 */
regs->GR_L(r1) = n1;
regs->psw.cc = 1;
/* Release main-storage access lock */
RELEASE_MAINLOCK(regs);
}
/* Perform serialization after completing operation */
PERFORM_SERIALIZATION (regs);
}
#endif /*defined(FEATURE_BROADCASTED_PURGING)*/
/*-------------------------------------------------------------------*/
/* 83 DIAG - Diagnose */
/*-------------------------------------------------------------------*/
DEF_INST(diagnose)
{
int r1, r3; /* Register numbers */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
RS(inst, execflag, regs, r1, r3, b2, effective_addr2);
#ifdef FEATURE_HERCULES_DIAGCALLS
if (
#if defined(_FEATURE_SIE)
!regs->sie_state &&
#endif /* defined(_FEATURE_SIE) */
effective_addr2 != 0xF08)
#endif
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
/* Process diagnose instruction */
ARCH_DEP(diagnose_call) (effective_addr2, r1, r3, regs);
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
#ifdef FEATURE_HERCULES_DIAGCALLS
RETURN_INTCHECK(regs);
#endif
}
#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, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(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 ( regs->psw.prob
&& (regs->CR(0) & CR0_EXT_AUTH) == 0 )
ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
/* Load R1 with PASN from control register 4 bits 16-31 */
regs->GR_L(r1) = regs->CR_LHL(4);
}
#endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/
#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, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(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 ( regs->psw.prob
&& (regs->CR(0) & CR0_EXT_AUTH) == 0 )
ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
/* Load R1 with SASN from control register 3 bits 16-31 */
regs->GR_L(r1) = regs->CR_LHL(3);
}
#endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/
#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, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(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);
INVALIDATE_AEA_ALL(regs);
}
#endif /*defined(FEATURE_LINKAGE_STACK)*/
#if defined(FEATURE_LINKAGE_STACK)
/*-------------------------------------------------------------------*/
/* B24A ESTA - Extract Stacked State [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(extract_stacked_state)
{
int r1, r2; /* Values of R fields */
BYTE code; /* Extraction code */
LSED lsed; /* Linkage stack entry desc. */
VADR lsea; /* Linkage stack entry addr */
#undef MAX_ESTA_CODE
#if defined(FEATURE_ESAME)
#define MAX_ESTA_CODE 4
#else /*!defined(FEATURE_ESAME)*/
#define MAX_ESTA_CODE 3
#endif /*!defined(FEATURE_ESAME)*/
RRE(inst, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(regs);
if (REAL_MODE(&regs->psw)
|| SECONDARY_SPACE_MODE(&regs->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);
/* Program check if r1 is odd, or if extraction code is invalid */
if ((r1 & 1) || code > MAX_ESTA_CODE)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
/* Find the virtual address of the entry descriptor
of the current state entry in the linkage stack */
lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs);
/* Load general register pair from state entry */
ARCH_DEP(stack_extract) (lsea, r1, code, regs);
/* Set condition code depending on entry type */
regs->psw.cc = ((lsed.uet & LSED_UET_ET) == LSED_UET_PC) ? 1 : 0;
}
#endif /*defined(FEATURE_LINKAGE_STACK)*/
#if defined(FEATURE_DUAL_ADDRESS_SPACE)
/*-------------------------------------------------------------------*/
/* B224 IAC - Insert Address Space Control [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(insert_address_space_control)
{
int r1, r2; /* Values of R fields */
RRE(inst, execflag, regs, r1, r2);
/* Special operation exception if DAT is off */
if ( REAL_MODE(&(regs->psw))
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
/* Except in XC mode */
&& !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC) )
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Privileged operation exception if in problem state
and the extraction-authority control bit is zero */
if ( regs->psw.prob
&& !(regs->CR(0) & CR0_EXT_AUTH)
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
/* Ignore extraction control in XC mode */
&& !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC) )
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
)
ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
/* Extract the address-space control bits from the PSW */
regs->psw.cc = (regs->psw.armode << 1) | (regs->psw.space);
/* Insert address-space mode into register bits 22-23 */
regs->GR_LHLCH(r1) = regs->psw.cc;
}
#endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/
/*-------------------------------------------------------------------*/
/* B20B IPK - Insert PSW Key [S] */
/*-------------------------------------------------------------------*/
DEF_INST(insert_psw_key)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
S(inst, execflag, regs, b2, effective_addr2);
/* Privileged operation exception if in problem state
and the extraction-authority control bit is zero */
if ( regs->psw.prob
&& (regs->CR(0) & CR0_EXT_AUTH) == 0 )
ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
/* Insert PSW key into bits 24-27 of general register 2
and set bits 28-31 of general register 2 to zero */
regs->GR_LHLCL(2) = regs->psw.pkey & 0xF0;
}
#if defined(FEATURE_BASIC_STORAGE_KEYS)
/*-------------------------------------------------------------------*/
/* 09 ISK - Insert Storage Key [RR] */
/*-------------------------------------------------------------------*/
DEF_INST(insert_storage_key)
{
int r1, r2; /* Values of R fields */
RADR n; /* Absolute storage addr */
#if defined(_FEATURE_SIE)
BYTE storkey;
#endif /*defined(_FEATURE_SIE)*/
RR(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
#if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE)
if(
#if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS)
regs->sie_state &&
#endif
!(regs->CR(0) & CR0_STORKEY_4K) )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#endif
/* Program check if R2 bits 28-31 are not zeroes */
if ( regs->GR_L(r2) & 0x0000000F )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
/* Load 2K block address from R2 register */
n = regs->GR_L(r2) & 0x00FFF800;
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state)
{
if(regs->siebk->ic[2] & SIE_IC2_ISKE)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
if(!regs->sie_pref)
{
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
&& (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY))
{
SIE_TRANSLATE(&n, ACCTYPE_SIE, regs);
#if !defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE;
#else
regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE;
#endif
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
U16 xcode;
int private,
protect,
stid;
RADR rcpa;
BYTE rcpkey;
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
{
/* guest absolute to host PTE addr */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private,
&protect, &stid))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
/* Convert real address to absolute address */
rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX);
/* The reference and change byte is located directly
beyond the page table and is located at offset 1 in
the entry. S/370 mode cannot be emulated in ESAME
mode, so no provision is made for ESAME mode tables */
rcpa += 1025;
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
/* Obtain address of the RCP area from the state desc */
rcpa = regs->sie_rcpo &= 0x7FFFF000;
/* frame index as byte offset to 4K keys in RCP area */
rcpa += n >> 12;
/* host primary to host absolute */
rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, 0);
}
/* fetch the RCP key */
rcpkey = sysblk.mainstor[rcpa];
STORAGE_KEY(rcpa) |= STORKEY_REF;
/* The storage key is obtained by logical or
or the real and guest RC bits */
storkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE);
/* guest absolute to host real */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private,
&protect, &stid))
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
{
/* In case of storage key assist obtain the
key and fetch bit from the PGSTE */
if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
regs->GR_LHLCL(r1) = storkey | (sysblk.mainstor[rcpa-1]
& (STORKEY_KEY | STORKEY_FETCH));
else
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
}
else
#else /*!defined(_FEATURE_STORAGE_KEY_ASSIST)*/
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
/* host real to host absolute */
n = APPLY_PREFIXING(n, regs->hostregs->PX);
#if !defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = storkey
| (STORAGE_KEY(n) & 0xFE);
#else
regs->GR_LHLCL(r1) = storkey
| ((STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE);
#endif
}
}
}
else /* !sie_pref */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE;
#else
regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE;
#endif
}
else /* !sie_state */
#endif /*defined(_FEATURE_SIE)*/
/* Insert the storage key into R1 register bits 24-31 */
#if defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE;
#else
regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE;
#endif
/* In BC mode, clear bits 29-31 of R1 register */
if ( regs->psw.ecmode == 0 )
regs->GR_LHLCL(r1) &= 0xF8;
// /*debug*/logmsg("ISK storage block %8.8X key %2.2X\n",
// regs->GR_L(r2), regs->GR_L(r1) & 0xFE);
}
#endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/
#if defined(FEATURE_EXTENDED_STORAGE_KEYS)
/*-------------------------------------------------------------------*/
/* B229 ISKE - Insert Storage Key Extended [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(insert_storage_key_extended)
{
int r1, r2; /* Values of R fields */
RADR n; /* Workarea */
#if defined(_FEATURE_SIE)
BYTE storkey;
#endif /*defined(_FEATURE_SIE)*/
RRE(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
/* Load 4K block address from R2 register */
n = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state)
{
if(regs->siebk->ic[2] & SIE_IC2_ISKE)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
if(!regs->sie_pref)
{
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY))
{
SIE_TRANSLATE(&n, ACCTYPE_SIE, regs);
/* Insert the storage key into R1 register bits 24-31 */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE;
#else
regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE;
#endif
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
U16 xcode;
int private,
protect,
stid;
RADR rcpa;
BYTE rcpkey;
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
)
{
/* guest absolute to host PTE addr */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private,
&protect, &stid))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
/* Convert real address to absolute address */
rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX);
/* For ESA/390 the RCP byte entry is at offset 1 in a
four byte entry directly beyond the page table,
for ESAME mode, this entry is eight bytes long */
rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025;
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
if(regs->siebk->mx & SIE_MX_XC)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
/* Obtain address of the RCP area from the state desc */
rcpa = regs->sie_rcpo &= 0x7FFFF000;
/* frame index as byte offset to 4K keys in RCP area */
rcpa += n >> 12;
/* host primary to host absolute */
rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, 0);
}
/* fetch the RCP key */
rcpkey = sysblk.mainstor[rcpa];
STORAGE_KEY(rcpa) |= STORKEY_REF;
/* The storage key is obtained by logical or
or the real and guest RC bits */
storkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE);
/* guest absolute to host real */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private,
&protect, &stid))
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
{
/* In case of storage key assist obtain the
key and fetch bit from the PGSTE */
if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
regs->GR_LHLCL(r1) = storkey | (sysblk.mainstor[rcpa-1]
& (STORKEY_KEY | STORKEY_FETCH));
else
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
}
else
#else /*!defined(_FEATURE_STORAGE_KEY_ASSIST)*/
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
/* host real to host absolute */
n = APPLY_PREFIXING(n, regs->hostregs->PX);
/* Insert the storage key into R1 register bits 24-31 */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = storkey | (STORAGE_KEY(n) & 0xFE);
#else
regs->GR_LHLCL(r1) = storkey | ((STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE);
#endif
}
}
}
else /* sie_pref */
/* Insert the storage key into R1 register bits 24-31 */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE;
#else
regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE;
#endif
}
else /* !sie_state */
#endif /*defined(_FEATURE_SIE)*/
/* Insert the storage key into R1 register bits 24-31 */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE;
#else
regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE;
#endif
} /* end DEF_INST(insert_storage_key_extended) */
#endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/
/*-------------------------------------------------------------------*/
/* B223 IVSK - Insert Virtual Storage Key [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(insert_virtual_storage_key)
{
int r1, r2; /* Values of R fields */
VADR effective_addr; /* Virtual storage addr */
U16 xcode; /* Exception code */
int private; /* 1=Private address space */
int protect; /* 1=ALE or page protection */
int stid; /* Segment table indication */
RADR n; /* 32-bit operand values */
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
int sr; /* SIE_TRANSLATE_ADDR rc */
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
RRE(inst, execflag, regs, r1, r2);
/* Special operation exception if DAT is off */
if ( (regs->psw.sysmask & PSW_DATMODE) == 0 )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Privileged operation exception if in problem state
and the extraction-authority control bit is zero */
if ( regs->psw.prob
&& (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,
&n, &xcode, &private, &protect, &stid))
ARCH_DEP(program_interrupt) (regs, xcode);
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
/* When running under SIE, and the guest absolute address
is paged out, then obtain the storage key from the
SPGTE rather then causing a host page fault. */
if(regs->sie_state
&& !regs->sie_pref
&& ((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
) && !(regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY))
{
/* guest absolute to host absolute addr or PTE addr in case of rc2 */
sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private,
&protect, &stid);
n = APPLY_PREFIXING (n, regs->hostregs->PX);
if(sr != 0 && sr != 2)
ARCH_DEP(program_interrupt) (regs->hostregs, xcode);
if(sr == 2)
{
/* For ESA/390 the RCP byte entry is at offset 0 in a
four byte entry directly beyond the page table,
for ESAME mode, this entry is eight bytes long */
n += regs->hostregs->arch_mode == ARCH_900 ? 2048 : 1024;
/* Insert PGSTE key bits 0-4 into R1 register bits
56-60 and set bits 61-63 to zeroes */
regs->GR_LHLCL(r1) = sysblk.mainstor[n] & 0xF8;
}
else
/* Insert storage key bits 0-4 into R1 register bits
56-60 and set bits 61-63 to zeroes */
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xF8;
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
SIE_TRANSLATE(&n, ACCTYPE_SIE, regs);
/* Insert storage key bits 0-4 into R1 register bits
56-60 and set bits 61-63 to zeroes */
regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xF8;
}
} /* end DEF_INST(insert_virtual_storage_key) */
/*-------------------------------------------------------------------*/
/* B221 IPTE - Invalidate Page Table Entry [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(invalidate_page_table_entry)
{
int r1, r2; /* Values of R fields */
RRE(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[0] & SIE_IC0_IPTECSP))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Perform serialization before operation */
PERFORM_SERIALIZATION (regs);
OBTAIN_MAINLOCK(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && regs->sie_scao)
{
STORAGE_KEY(regs->sie_scao) |= STORKEY_REF;
if(sysblk.mainstor[regs->sie_scao] & 0x80)
{
RELEASE_MAINLOCK(regs);
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
}
sysblk.mainstor[regs->sie_scao] |= 0x80;
STORAGE_KEY(regs->sie_scao) |= (STORKEY_REF|STORKEY_CHANGE);
}
#endif /*defined(_FEATURE_SIE)*/
/* Invalidate page table entry */
ARCH_DEP(invalidate_pte) (inst[1], r1, r2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && regs->sie_scao)
{
sysblk.mainstor[regs->sie_scao] &= 0x7F;
STORAGE_KEY(regs->sie_scao) |= (STORKEY_REF|STORKEY_CHANGE);
}
#endif /*defined(_FEATURE_SIE)*/
/* Mainlock now released by `invalidate_pte' */
// RELEASE_MAINLOCK(regs);
}
#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;
U16 pkm_d;
U16 sasn_d;
U16 ax_d;
U16 pasn_d;
U32 aste[16]; /* ASN second table entry */
RADR pstd; /* Primary STD */
RADR sstd; /* Secondary STD */
U32 ltd; /* Linkage table designation */
U32 pasteo; /* Primary ASTE origin */
U32 sasteo; /* Secondary ASTE origin */
U16 ax; /* Authorisation index */
#ifdef FEATURE_SUBSPACE_GROUP
U16 xcode; /* Exception code */
#endif /*FEATURE_SUBSPACE_GROUP*/
SSE(inst, execflag, regs, b1, effective_addr1, b2, effective_addr2);
SIE_MODE_XC_OPEX(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(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_LASP))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Fetch PKM, SASN, AX, and PASN from first operand */
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;
INVALIDATE_AEA_ALL(regs);
/* 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;
}
INVALIDATE_AIA(regs);
/* Obtain new PSTD and LTD from ASTE */
pstd = ASTE_AS_DESIGNATOR(aste);
ltd = ASTE_LT_DESIGNATOR(aste);
ax = (aste[1] & ASTE1_AX) >> 16;
#ifdef FEATURE_SUBSPACE_GROUP
/* Perform subspace replacement on new PSTD */
pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, &xcode, regs);
/* Return with condition code 1 if ASTE exception recognized */
if (xcode != 0)
{
regs->psw.cc = 1;
return;
}
#endif /*FEATURE_SUBSPACE_GROUP*/
/* Return with condition code 3 if either current STD
or new STD indicates a space switch event */
if ((regs->CR(1) & SSEVENT_BIT)
|| (ASTE_AS_DESIGNATOR(aste) & SSEVENT_BIT))
{
regs->psw.cc = 3;
return;
}
}
else
{
/* Load current PSTD and LTD or PASTEO */
pstd = regs->CR(1);
ltd = regs->CR_L(5);
pasteo = regs->CR_L(5);
ax = (regs->CR(4) & CR4_AX) >> 16;
}
/* 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 */
if (sasn_d == pasn_d)
{
sstd = pstd;
}
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 in control register 7 */
if (!(effective_addr2 & 0x00000004)
&& (effective_addr2 & 0x00000001)
&& (sasn_d == regs->CR_LHL(3)))
{
sstd = regs->CR(7);
}
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;
}
/* Obtain new SSTD or SASCE from secondary ASTE */
sstd = ASTE_AS_DESIGNATOR(aste);
#ifdef FEATURE_SUBSPACE_GROUP
/* Perform subspace replacement on new SSTD */
sstd = ARCH_DEP(subspace_replace) (sstd, sasteo,
&xcode, regs);
/* Return condition code 2 if ASTE exception recognized */
if (xcode != 0)
{
regs->psw.cc = 2;
return;
}
#endif /*FEATURE_SUBSPACE_GROUP*/
/* Perform SASN authorization if bit 31 of the
LASP function bits is 0 */
if (!(effective_addr2 & 0x00000001))
{
/* Condition code 2 if SASN authorization fails */
if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY,
regs))
{
regs->psw.cc = 2;
return;
}
} /* end if(SASN authorization) */
} /* end if(SASN translation) */
} /* end if(SASN = PASN) */
/* Perform control-register loading */
regs->CR(1) = pstd;
regs->CR_LHH(3) = pkm_d;
regs->CR_LHL(3) = sasn_d;
regs->CR_LHH(4) = ax;
regs->CR_LHL(4) = pasn_d;
regs->CR_L(5) = ASF_ENABLED(regs) ? pasteo : ltd;
regs->CR(7) = sstd;
/* Return condition code zero */
regs->psw.cc = 0;
}
#endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/
/*-------------------------------------------------------------------*/
/* B7 LCTL - Load Control [RS] */
/*-------------------------------------------------------------------*/
DEF_INST(load_control)
{
int r1, r3; /* Register numbers */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
int i, d; /* Integer work areas */
BYTE rwork[64]; /* Register work areas */
#if defined(FEATURE_CHANNEL_SUBSYSTEM)
BYTE dism; /* Disabled int subcl mask */
#elif defined(FEATURE_S370_CHANNEL)
U32 dchn; /* Disabled channel mask */
#endif
RS(inst, execflag, regs, r1, r3, b2, effective_addr2);
PRIV_CHECK(regs);
FW_CHECK(effective_addr2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state)
{
U32 n;
for(i = r1; ; )
{
n = 0x8000 >> i;
if(regs->siebk->lctl_ctl[i < 8 ? 0 : 1] & ((i < 8) ? n >> 8 : n))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
if ( i == r3 ) break;
i++; i &= 15;
}
}
#endif /*defined(_FEATURE_SIE)*/
/* Calculate the number of bytes to be loaded */
d = (((r3 < r1) ? r3 + 16 - r1 : r3 - r1) + 1) * 4;
/* Fetch new control register contents from operand address */
ARCH_DEP(vfetchc) ( rwork, d-1, effective_addr2, b2, regs );
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
#if defined(FEATURE_CHANNEL_SUBSYSTEM)
/* Save disabled I/O subclasses */
dism = ~regs->CR_LHHCH(6);
#elif defined(FEATURE_S370_CHANNEL)
/* Save disabled channel mask */
dchn = ~regs->CR_L(2);
#endif
/* Load control registers from work area */
for ( i = r1, d = 0; ; )
{
/* Load control register bits 32-63 from work area */
FETCH_FW(regs->CR_L(i), rwork + d); d += 4;
/* Instruction is complete when r3 register is done */
if ( i == r3 ) break;
/* Update register number, wrapping from 15 to 0 */
i++; i &= 15;
}
#if defined(FEATURE_CHANNEL_SUBSYSTEM)
/* Force I/O interrupt check when enabling an I/O subclass */
if(dism & regs->CR_LHHCH(6))
#elif defined(FEATURE_S370_CHANNEL)
if(dchn & regs->CR_L(2));
#endif
{
obtain_lock(&sysblk.intlock);
ON_IC_IOPENDING;
release_lock(&sysblk.intlock);
}
SET_IC_EXTERNAL_MASK(regs);
SET_IC_MCK_MASK(regs);
SET_IC_PER_MASK(regs);
RETURN_INTCHECK(regs);
} /* end DEF_INST(load_control) */
/*-------------------------------------------------------------------*/
/* 82 LPSW - Load Program Status Word [S] */
/*-------------------------------------------------------------------*/
DEF_INST(load_program_status_word)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
DWORD dword;
int rc;
#if defined(FEATURE_ESAME)
int amode64;
#endif /*defined(FEATURE_ESAME)*/
S(inst, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
DW_CHECK(effective_addr2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_LPSW))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Perform serialization and checkpoint synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
/* Fetch new PSW from operand address */
ARCH_DEP(vfetchc) ( dword, 8-1, effective_addr2, b2, regs );
/* Load updated PSW (ESA/390 Format in ESAME mode) */
#if defined(FEATURE_ESAME)
/* save amode64 flag */
amode64 = dword[3] & 0x01;
/* make psw valid for esa390 mode */
dword[3] &= ~0x01;
if ( ( rc = s390_load_psw ( regs, dword ) ) )
{
regs->psw.notesame = 0;
#else /*!defined(FEATURE_ESAME)*/
if ( ( rc = ARCH_DEP(load_psw) ( regs, dword ) ) )
{
#endif /*!defined(FEATURE_ESAME)*/
ARCH_DEP(program_interrupt) (regs, rc);
}
/* load_psw() has set the ILC to zero. This needs to
be reset to 4 for an eventual PER event */
regs->psw.ilc = 4;
#if defined(FEATURE_ESAME)
/* Set the notesame bit to zero as it has been set,
and clear the high word of the instruction address,
as it has not been touched by s390_load_psw */
regs->psw.notesame = 0;
regs->psw.amode64 = amode64;
regs->psw.IA_H = 0;
#endif /*defined(FEATURE_ESAME)*/
/* Perform serialization and checkpoint synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
RETURN_INTCHECK(regs);
} /* end DEF_INST(load_program_status_word) */
/*-------------------------------------------------------------------*/
/* B1 LRA - Load Real Address [RX] */
/*-------------------------------------------------------------------*/
DEF_INST(load_real_address)
{
int r1; /* Register number */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
U16 xcode; /* Exception code */
int private; /* 1=Private address space */
int protect; /* 1=ALE or page protection */
int stid; /* Segment table indication */
int cc; /* Condition code */
RADR n; /* 32-bit operand values */
RX(inst, execflag, regs, r1, b2, effective_addr2);
SIE_MODE_XC_OPEX(regs);
PRIV_CHECK(regs);
/* Translate the effective address to a real address */
cc = ARCH_DEP(translate_addr) (effective_addr2, b2, regs,
ACCTYPE_LRA, &n, &xcode, &private, &protect, &stid);
/* 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 | xcode;
cc = 3;
}
else
{
/* Set r1 and condition code as returned by translate_addr */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64 && cc != 3)
{
regs->GR_G(r1) = n;
}
else
{
if (n <= 0x7FFFFFFF)
{
regs->GR_L(r1) = n;
}
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 | xcode;
cc = 3;
} /* end else(n) */
} /* end else(amode) */
#else /*!defined(FEATURE_ESAME)*/
regs->GR_L(r1) = n;
#endif /*!defined(FEATURE_ESAME)*/
} /* end else(cc) */
regs->psw.cc = cc;
} /* end DEF_INST(load_real_address) */
/*-------------------------------------------------------------------*/
/* 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, execflag, regs, r1, r2);
PRIV_CHECK(regs);
/* R2 register contains operand real storage address */
n = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
/* Program check if operand not on fullword boundary */
FW_CHECK(n, regs);
/* Load R1 register from second operand */
regs->GR_L(r1) = ARCH_DEP(vfetch4) ( n, USE_REAL_ADDR, regs );
}
#if defined(FEATURE_LOCK_PAGE)
/*-------------------------------------------------------------------*/
/* B262 LKPG - Lock Page [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(lock_page)
{
int r1, r2; /* Values of R fields */
VADR n2; /* effective addr of r2 */
RADR raddr, /* Real address */
rpte; /* PTE real address */
CREG pte; /* Page Table Entry */
int private; /* 1=Private address space */
int protect; /* 1=ALE or page protection */
int stid; /* Segment table indication */
U16 xcode = 0; /* Exception code */
RRE(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
if(REAL_MODE(&(regs->psw)))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
if(regs->GR_L(0) & LKPG_GPR0_RESV)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
n2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
/* Access to PTE must be serialized */
OBTAIN_MAINLOCK(regs);
/* Return condition code 3 if translation exception */
ARCH_DEP(translate_addr) (n2, r2, regs, ACCTYPE_PTE,
&rpte, &xcode, &private, &protect, &stid);
if (xcode == 0)
{
rpte = APPLY_PREFIXING (rpte, regs->PX);
pte =
#if defined(FEATURE_ESAME)
ARCH_DEP(fetch_doubleword_absolute) (rpte, regs);
#else /*!defined(FEATURE_ESAME)*/
ARCH_DEP(fetch_fullword_absolute) (rpte, regs);
#endif /*!defined(FEATURE_ESAME)*/
if(regs->GR_L(0) & LKPG_GPR0_LOCKBIT)
{
/* Lock request */
if(!(pte & PAGETAB_PGLOCK))
{
/* Return condition code 3 if translation exception */
if(ARCH_DEP(translate_addr) (n2, r2, regs, ACCTYPE_LRA,
&raddr, &xcode, &private, &protect, &stid))
{
regs->psw.cc = 3;
RELEASE_MAINLOCK(regs);
return;
}
pte |= PAGETAB_PGLOCK;
#if defined(FEATURE_ESAME)
ARCH_DEP(store_doubleword_absolute) (pte, rpte, regs);
#else /*!defined(FEATURE_ESAME)*/
ARCH_DEP(store_fullword_absolute) (pte, rpte, regs);
#endif /*!defined(FEATURE_ESAME)*/
regs->GR(r1) = raddr;
regs->psw.cc = 0;
}
else
regs->psw.cc = 1;
}
else
{
/* Unlock reguest */
if(pte & PAGETAB_PGLOCK)
{
pte &= ~((U64)PAGETAB_PGLOCK);
#if defined(FEATURE_ESAME)
ARCH_DEP(store_doubleword_absolute) (pte, rpte, regs);
#else /*!defined(FEATURE_ESAME)*/
ARCH_DEP(store_fullword_absolute) (pte, rpte, regs);
#endif /*!defined(FEATURE_ESAME)*/
regs->psw.cc = 0;
}
else
regs->psw.cc = 1;
}
}
else
regs->psw.cc = 3;
RELEASE_MAINLOCK(regs);
} /* end DEF_INST(lock_page) */
#endif /*defined(FEATURE_LOCK_PAGE)*/
#if defined(FEATURE_LINKAGE_STACK)
/*-------------------------------------------------------------------*/
/* B247 MSTA - Modify Stacked State [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(modify_stacked_state)
{
int r1, unused; /* Values of R fields */
U32 m1, m2; /* Modify values */
LSED lsed; /* Linkage stack entry desc. */
VADR lsea; /* Linkage stack entry addr */
RRE(inst, execflag, regs, r1, unused);
SIE_MODE_XC_OPEX(regs);
if (REAL_MODE(&regs->psw)
|| SECONDARY_SPACE_MODE(&regs->psw)
|| !ASF_ENABLED(regs))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
ODD_CHECK(r1, regs);
/* Find the virtual address of the entry descriptor
of the current state entry in the linkage stack */
lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs);
/* Load values from rightmost 32 bits of R1 and R1+1 registers */
m1 = regs->GR_L(r1);
m2 = regs->GR_L(r1+1);
/* Store two 32-bit values into modifiable area of state entry */
ARCH_DEP(stack_modify) (lsea, m1, m2, regs);
}
#endif /*defined(FEATURE_LINKAGE_STACK)*/
/*-------------------------------------------------------------------*/
/* DA MVCP - Move to Primary [SS] */
/*-------------------------------------------------------------------*/
DEF_INST(move_to_primary)
{
int r1, r3; /* Register numbers */
int b1, b2; /* Values of base registers */
VADR effective_addr1,
effective_addr2; /* Effective addresses */
int cc; /* Condition code */
int k; /* Integer workarea */
GREG l; /* Unsigned workarea */
SS(inst, execflag, regs, r1, r3, b1, effective_addr1,
b2, effective_addr2);
SIE_MODE_XC_OPEX(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(&regs->psw)
|| regs->psw.armode)
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 ( regs->psw.prob
&& ((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;
}
/*-------------------------------------------------------------------*/
/* DB MVCS - Move to Secondary [SS] */
/*-------------------------------------------------------------------*/
DEF_INST(move_to_secondary)
{
int r1, r3; /* Register numbers */
int b1, b2; /* Values of base registers */
VADR effective_addr1,
effective_addr2; /* Effective addresses */
int cc; /* Condition code */
int k; /* Integer workarea */
GREG l; /* Unsigned workarea */
SS(inst, execflag, regs, r1, r3, b1, effective_addr1,
b2, effective_addr2);
SIE_MODE_XC_OPEX(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(&regs->psw)
|| regs->psw.armode)
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 ( regs->psw.prob
&& ((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;
}
/*-------------------------------------------------------------------*/
/* 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, execflag, regs, b1, effective_addr1, b2, effective_addr2);
/* Load operand length-1 from register 0 bits 24-31 */
l = regs->GR_L(0) & 0xFF;
/* Load destination key from register 1 bits 24-27 */
k = regs->GR_L(1) & 0xF0;
/* Program check if in problem state and key mask in
CR3 bits 0-15 is not 1 for the specified key */
if ( regs->psw.prob
&& ((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);
}
/*-------------------------------------------------------------------*/
/* D9 MVCK - Move with Key [SS] */
/*-------------------------------------------------------------------*/
DEF_INST(move_with_key)
{
int r1, r3; /* Register numbers */
int b1, b2; /* Values of base registers */
VADR effective_addr1,
effective_addr2; /* Effective addresses */
int cc; /* Condition code */
int k; /* Integer workarea */
GREG l; /* Unsigned workarea */
SS(inst, execflag, regs, r1, r3, b1, effective_addr1,
b2, effective_addr2);
/* Load true length from R1 register */
l = GR_A(r1,regs);
/* If the true length does not exceed 256, set condition code
zero, otherwise set cc=3 and use effective length of 256 */
if (l <= 256)
cc = 0;
else {
cc = 3;
l = 256;
}
/* Load source key from R3 register bits 24-27 */
k = regs->GR_L(r3) & 0xF0;
/* Program check if in problem state and key mask in
CR3 bits 0-15 is not 1 for the specified key */
if ( regs->psw.prob
&& ((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;
}
/*-------------------------------------------------------------------*/
/* 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, execflag, regs, b1, effective_addr1, b2, effective_addr2);
/* Load operand length-1 from register 0 bits 24-31 */
l = regs->GR_L(0) & 0xFF;
/* Load source key from register 1 bits 24-27 */
k = regs->GR_L(1) & 0xF0;
/* Program check if in problem state and key mask in
CR3 bits 0-15 is not 1 for the specified key */
if ( regs->psw.prob
&& ((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 */
VADR effective_addr2; /* Effective address */
RADR abs; /* Absolute address */
RADR pstd; /* Primary STD or ASCE */
U32 oldpstd; /* Old Primary STD or ASCE */
U32 ltd; /* Linkage table designation */
U32 pasteo; /* Primary ASTE origin */
RADR lto; /* Linkage table origin */
int ltl; /* Linkage table length */
U32 lte; /* Linkage table entry */
RADR eto; /* Entry table origin */
int etl; /* Entry table length */
U32 ete[8]; /* Entry table entry */
int numwords; /* ETE size (4 or 8 words) */
int i; /* Array subscript */
int ssevent = 0; /* 1=space switch event */
U32 aste[16]; /* ASN second table entry */
U32 akm; /* Bits 0-15=AKM, 16-31=zero */
U16 xcode; /* Exception code */
U16 pasn; /* Primary ASN */
U16 oldpasn; /* Old Primary ASN */
#if defined(FEATURE_LINKAGE_STACK)
U32 csi; /* Called-space identifier */
VADR retn; /* Return address and amode */
#endif /*defined(FEATURE_LINKAGE_STACK)*/
#ifdef FEATURE_TRACING
CREG newcr12 = 0; /* CR12 upon completion */
#endif /*FEATURE_TRACING*/
S(inst, execflag, regs, b2, effective_addr2);
SIE_MODE_XC_OPEX(regs);
INVALIDATE_AEA_ALL(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_PC))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
/* Load the PC number from the low-order 20 bits of the operand */
pcnum = effective_addr2 & (PC_LX | PC_EX);
/* Special operation exception if DAT is off, or if
in secondary space mode or home space mode */
if (REAL_MODE(&(regs->psw)) || regs->psw.space == 1)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* save CR4 and CR1 incase 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 */
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->mainsize)
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Fetch primary ASTE words 3 or 6 from absolute storage
(note: the ASTE cannot cross a page boundary) */
#if !defined(FEATURE_ESAME)
aste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs);
#else /*defined(FEATURE_ESAME)*/
aste[6] = ARCH_DEP(fetch_fullword_absolute) (abs+24, regs);
#endif /*defined(FEATURE_ESAME)*/
/* Load LTD from primary ASTE word 3 or 6 */
ltd = ASTE_LT_DESIGNATOR(aste);
}
#ifdef FEATURE_TRACING
/* Form trace entry if ASN tracing is active */
if (regs->CR(12) & CR12_ASNTRACE)
newcr12 = ARCH_DEP(trace_pc) (pcnum, regs);
#endif /*FEATURE_TRACING*/
/* 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);
/* [5.5.3.2] Linkage table lookup */
/* Extract the linkage table origin and length from the LTD */
lto = ltd & LTD_LTO;
ltl = ltd & LTD_LTL;
/* Program check if linkage index is outside the linkage table */
if (ltl < ((pcnum & PC_LX) >> 13))
{
regs->TEA = pcnum;
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 is outside real storage */
if (lto >= regs->mainsize)
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 linkage entry invalid bit is set */
if (lte & LTE_INVALID)
{
regs->TEA = pcnum;
ARCH_DEP(program_interrupt) (regs, PGM_LX_TRANSLATION_EXCEPTION);
}
/* [5.5.3.3] Entry table lookup */
/* Extract the entry table origin and length from the LTE */
eto = lte & LTE_ETO;
etl = lte & LTE_ETL;
/* Program check if entry index is outside the entry table */
if (etl < ((pcnum & PC_EX) >> 2))
{
regs->TEA = pcnum;
ARCH_DEP(program_interrupt) (regs, PGM_EX_TRANSLATION_EXCEPTION);
}
/* Calculate the starting address of the entry table entry */
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;
/* 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 cannot cross a page boundary. */
for (i = 0; i < numwords; i++)
{
/* Program check if address is outside main storage */
abs = APPLY_PREFIXING (eto, regs->PX);
if (abs >= regs->mainsize)
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Fetch one word of the entry table entry */
ete[i] = ARCH_DEP(fetch_fullword_absolute) (abs, regs);
eto += 4;
eto &= 0x7FFFFFFF;
}
/* 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 && regs->psw.armode)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#if defined(FEATURE_ESAME)
/* Program check if basic program call is attempting
to switch into or out of 64-bit addressing mode */
if ((ete[4] & ETE4_T) == 0
&& ((ete[4] & ETE4_G) ? 1 : 0) != regs->psw.amode64)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#endif /*defined(FEATURE_ESAME)*/
/* Program check if resulting addressing mode is 24 and the
entry instruction address is not a 24-bit address */
if ((ete[1] & ETE1_AMODE) == 0
#if defined(FEATURE_ESAME)
&& (ete[4] & ETE4_G) == 0
#endif /*defined(FEATURE_ESAME)*/
&& (ete[1] & ETE1_EIA) > 0x00FFFFFF)
ARCH_DEP(program_interrupt) (regs, PGM_PC_TRANSLATION_SPECIFICATION_EXCEPTION);
/* Obtain the authorization key mask from the entry table */
#if defined(FEATURE_ESAME)
akm = ete[2] & ETE2_AKM;
#else /*!defined(FEATURE_ESAME)*/
akm = ete[0] & ETE0_AKM;
#endif /*!defined(FEATURE_ESAME)*/
/* Program check if in problem state and the PKM in control
register 3 produces zero when ANDed with the AKM in the ETE */
if (regs->psw.prob
&& ((regs->CR(3) & CR3_KEYMASK) & akm) == 0)
ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
/* Obtain the new primary ASN from the entry table */
#if defined(FEATURE_ESAME)
pasn = ete[2] & ETE2_ASN;
#else /*!defined(FEATURE_ESAME)*/
pasn = ete[0] & ETE0_ASN;
#endif /*!defined(FEATURE_ESAME)*/
/* Obtain the ASTE if ASN is non-zero */
if (pasn != 0)
{
INVALIDATE_AIA(regs);
/* 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->mainsize)
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Fetch the 16-word ASTE from absolute storage
(note: the ASTE cannot cross a page boundary) */
for (i = 0; i < 16; i++)
{
aste[i] = ARCH_DEP(fetch_fullword_absolute) (abs, regs);
abs += 4;
}
/* ASX translation exception if ASTE invalid bit is one */
if (aste[0] & ASTE0_INVALID)
{
regs->TEA = pasn;
ARCH_DEP(program_interrupt) (regs, PGM_ASX_TRANSLATION_EXCEPTION);
}
}
/* Obtain the new PSTD or PASCE from the ASTE */
pstd = ASTE_AS_DESIGNATOR(aste);
#ifdef FEATURE_SUBSPACE_GROUP
/* Perform subspace replacement on new PSTD */
pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, NULL, regs);
#endif /*FEATURE_SUBSPACE_GROUP*/
} /* end if(PC-ss) */
else
{ /* PC-cp */
/* For PC to current primary, load current primary STD */
pstd = regs->CR(1);
} /* end if(PC-cp) */
/* Perform basic or stacking program call */
if ((ete[4] & ETE4_T) == 0)
{
/* For basic PC, load linkage info into general register 14 */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
regs->GR_G(14) = regs->psw.IA | regs->psw.prob;
else
regs->GR_L(14) = (regs->psw.amode ? 0x80000000 : 0)
| regs->psw.IA | regs->psw.prob;
#else /*!defined(FEATURE_ESAME)*/
regs->GR_L(14) = (regs->psw.amode ? 0x80000000 : 0)
| regs->psw.IA | regs->psw.prob;
#endif /*!defined(FEATURE_ESAME)*/
/* Update the PSW from the entry table */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
regs->psw.IA = ((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;
regs->psw.IA = ete[1] & ETE1_EIA;
}
#else /*!defined(FEATURE_ESAME)*/
regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0;
regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24;
regs->psw.IA = ete[1] & ETE1_EIA;
#endif /*!defined(FEATURE_ESAME)*/
regs->psw.prob = (ete[1] & ETE1_PROB) ? 1 : 0;
/* Load the current PKM and PASN into general register 3 */
regs->GR_L(3) = (regs->CR(3) & CR3_KEYMASK)
| (regs->CR(4) & CR4_PASN);
/* OR the EKM into the current PKM */
regs->CR(3) |= (ete[3] & ETE3_EKM);
/* Load the entry parameter into general register 4 */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
regs->GR_H(4) = ete[6];
regs->GR_L(4) = ete[7];
#else /*!defined(FEATURE_ESAME)*/
regs->GR_L(4) = ete[2];
#endif /*!defined(FEATURE_ESAME)*/
} /* end if(basic PC) */
else
#if defined(FEATURE_LINKAGE_STACK)
{ /* stacking PC */
/* ESA/390 POP Fig 10-17 8.B.11 */
if (!ASF_ENABLED(regs))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#if defined(FEATURE_ESAME)
/* Add a mode trace entry when switching in/out of 64 bit mode */
if((regs->CR(12) & CR12_MTRACE) && regs->psw.amode64 != (ete[4] & ETE4_G) ? 1 : 0)
ARCH_DEP(trace_ms) (0,((U64)(ete[0]) << 32) | (U64)(ete[1] & 0xFFFFFFFE), regs);
#endif /*defined(FEATURE_ESAME)*/
/* Set the called-space identification */
csi = (pasn == 0) ? 0 : pasn << 16 | (aste[5] & 0x0000FFFF);
/* Set the addressing mode bits in the return address */
retn = regs->psw.IA;
#if defined(FEATURE_ESAME)
if ( regs->psw.amode64 )
retn |= 0x01;
else
#endif /*defined(FEATURE_ESAME)*/
if ( regs->psw.amode )
retn |= 0x80000000;
#if defined(FEATURE_ESAME)
/* Set the high-order bit of the PC number if
the resulting addressing mode is 64-bit */
if (ete[4] & ETE4_G)
pcnum |= 0x80000000;
#endif /*defined(FEATURE_ESAME)*/
/* Perform the stacking process */
ARCH_DEP(form_stack_entry) (LSED_UET_PC, retn, 0, csi,
pcnum, regs);
/* Update the PSW from the entry table */
#if defined(FEATURE_ESAME)
if (ete[4] & ETE4_G)
{
regs->psw.amode64 = 1;
regs->psw.amode = 1;
regs->psw.AMASK = AMASK64;
regs->psw.IA = ((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;
regs->psw.IA = ete[1] & ETE1_EIA;
}
#else /*!defined(FEATURE_ESAME)*/
regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0;
regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24;
regs->psw.IA = ete[1] & ETE1_EIA;
#endif /*!defined(FEATURE_ESAME)*/
regs->psw.prob = (ete[1] & ETE1_PROB) ? 1 : 0;
/* Replace the PSW key by the entry key if the K bit is set */
if (ete[4] & ETE4_K) {
INVALIDATE_AIA(regs);
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 */
regs->psw.armode = (ete[4] & ETE4_C) ? 1 : 0;
/* Load the entry parameter into general register 4 */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
regs->GR_H(4) = ete[6];
regs->GR_L(4) = ete[7];
#else /*!defined(FEATURE_ESAME)*/
regs->GR_L(4) = ete[2];
#endif /*!defined(FEATURE_ESAME)*/
} /* end if(stacking PC) */
#else /*!defined(FEATURE_LINKAGE_STACK)*/
ARCH_DEP(program_interrupt) (regs, PGM_PC_TRANSLATION_SPECIFICATION_EXCEPTION);
#endif /*!defined(FEATURE_LINKAGE_STACK)*/
/* If new ASN is zero, perform program call to current primary */
if (pasn == 0)
{
/* Set SASN equal to PASN */
regs->CR_LHL(3) = regs->CR_LHL(4);
/* Set SSTD equal to PSTD */
regs->CR(7) = regs->CR(1);
} /* 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);
/* Set flag if either the current or new PSTD indicates
a space switch event */
if ((regs->CR(1) & SSEVENT_BIT)
|| (ASTE_AS_DESIGNATOR(aste) & 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;
/* 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);
}
#endif /*defined(FEATURE_LINKAGE_STACK)*/
} /* end if(PC-ss) */
#ifdef FEATURE_TRACING
/* Update trace table address if ASN tracing is active */
if (regs->CR(12) & CR12_ASNTRACE)
regs->CR(12) = newcr12;
#endif /*FEATURE_TRACING*/
#if defined(FEATURE_PER)
if( EN_IC_PER_SB(regs)
#if defined(FEATURE_PER2)
&& ( !(regs->CR(9) & CR9_BAC)
|| PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) )
#endif /*defined(FEATURE_PER2)*/
)
ON_IC_PER_SB(regs);
#endif /*defined(FEATURE_PER)*/
/* 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);
}
#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; /* Primary ASTE origin */
U32 sasteo; /* 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, execflag, regs);
SIE_MODE_XC_OPEX(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_PR))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
/* Create a working copy of the CPU registers */
newregs = *regs;
/* 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);
/* Perform PR-cp or PR-ss if unstacked entry was a program call */
if (etype == LSED_UET_PC)
{
/* Extract the new primary ASN from CR4 bits 16-31 */
pasn = newregs.CR_LHL(4);
#ifdef FEATURE_TRACING
/* Perform tracing if ASN tracing is on */
if (regs->CR(12) & CR12_ASNTRACE)
newregs.CR(12) = ARCH_DEP(trace_pr) (&newregs, regs);
#if defined(FEATURE_ESAME)
else
/* Add a mode trace entry when switching in/out of 64 bit mode */
if((regs->CR(12) & CR12_MTRACE) && regs->psw.amode64 != newregs.psw.amode64)
ARCH_DEP(trace_ms) (0, newregs.psw.IA, regs);
#endif /*defined(FEATURE_ESAME)*/
#endif /*FEATURE_TRACING*/
/* Perform PASN translation if new PASN not equal old PASN */
if (pasn != oldpasn)
{
/* Special operation exception if ASN translation
control (control register 14 bit 12) is zero */
if ((regs->CR(14) & CR14_ASN_TRAN) == 0)
ARCH_DEP(program_interrupt) (&newregs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Translate new primary ASN to obtain ASTE */
xcode = ARCH_DEP(translate_asn) (pasn, &newregs, &pasteo, aste);
/* Program check if ASN translation exception */
if (xcode != 0)
ARCH_DEP(program_interrupt) (&newregs, xcode);
/* Space switch if either current PSTD or new PSTD
space-switch-event control bit is set to 1 */
if ((regs->CR(1) & SSEVENT_BIT)
|| (ASTE_AS_DESIGNATOR(aste) & SSEVENT_BIT))
{
/* Indicate space-switch event required */
ssevent = 1;
}
else
{
/* space-switch event maybe - if PER event */
ssevent = 2;
}
/* Obtain new PSTD (or PASCE) and AX from the ASTE */
newregs.CR(1) = ASTE_AS_DESIGNATOR(aste);
newregs.CR_LHH(4) = 0;
newregs.CR_L(4) |= aste[1] & ASTE1_AX;
/* Load CR5 with the primary ASTE origin address */
newregs.CR_L(5) = pasteo;
#ifdef FEATURE_SUBSPACE_GROUP
/* Perform subspace replacement on new PSTD */
newregs.CR(1) = ARCH_DEP(subspace_replace) (newregs.CR(1),
pasteo, NULL, &newregs);
#endif /*FEATURE_SUBSPACE_GROUP*/
} /* 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 */
{
/* 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);
/* Obtain new SSTD or SASCE from secondary ASTE */
newregs.CR(7) = ASTE_AS_DESIGNATOR(aste);
/* Perform SASN authorization using new AX */
ax = newregs.CR_LHH(4);
if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY, &newregs))
{
newregs.TEA = sasn;
ARCH_DEP(program_interrupt) (&newregs, PGM_SECONDARY_AUTHORITY_EXCEPTION);
}
#ifdef FEATURE_SUBSPACE_GROUP
/* Perform subspace replacement on new SSTD */
newregs.CR(7) = ARCH_DEP(subspace_replace) (newregs.CR(7),
sasteo, NULL, &newregs);
#endif /*FEATURE_SUBSPACE_GROUP*/
} /* end else(sasn!=pasn) */
} /* end if(LSED_UET_PC) */
/* Update the updated CPU registers from the working copy */
memcpy(regs->gr, newregs.gr, sizeof(newregs.gr));
memcpy(regs->ar, newregs.ar, sizeof(newregs.ar));
memcpy(regs->cr, newregs.cr, sizeof(newregs.cr));
memcpy(&(regs->psw), &(newregs.psw), sizeof(newregs.psw));
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
SET_IC_EXTERNAL_MASK(regs);
SET_IC_MCK_MASK(regs);
SET_IC_IO_MASK(regs);
regs->psw.ilc = 2;
/* Set the main storage reference and change bits */
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*)(sysblk.mainstor + alsed);
lsedp->nes[0] = 0;
lsedp->nes[1] = 0;
#if defined(FEATURE_PER)
/* Copy PER info from working copy to real copy of registers */
if (IS_IC_PER_SA(&newregs))
{
ON_IC_PER_SA(regs);
regs->perc = newregs.perc;
}
if( EN_IC_PER_SB(regs)
#if defined(FEATURE_PER2)
&& ( !(regs->CR(9) & CR9_BAC)
|| PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) )
#endif /*defined(FEATURE_PER2)*/
)
ON_IC_PER_SB(regs);
#endif /*defined(FEATURE_PER)*/
/* 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 */
newregs.TEA = oldpasn;
if (oldpstd & SSEVENT_BIT)
newregs.TEA |= TEA_SSEVENT;
ARCH_DEP(program_interrupt) (&newregs, PGM_SPACE_SWITCH_EVENT);
}
if (rc) /* if new psw has bad format */
{
regs->psw.ilc = 0;
ARCH_DEP(program_interrupt) (&newregs, rc);
}
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
RETURN_INTCHECK(regs);
}
#endif /*defined(FEATURE_LINKAGE_STACK)*/
#if defined(FEATURE_DUAL_ADDRESS_SPACE)
/*-------------------------------------------------------------------*/
/* B228 PT - Program Transfer [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(program_transfer)
{
int r1, r2; /* Values of R fields */
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; /* Primary ASTE origin */
U32 aste[16]; /* ASN second table entry */
CREG pstd; /* Primary STD */
U32 oldpstd; /* Old Primary STD */
U16 ax; /* Authorization index */
U16 xcode; /* Exception code */
int ssevent = 0; /* 1=space switch event */
#ifdef FEATURE_TRACING
CREG newcr12 = 0; /* CR12 upon completion */
#endif /*FEATURE_TRACING*/
RRE(inst, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(regs);
INVALIDATE_AEA_ALL(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_PT))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
/* Special operation exception if DAT is off, or
not in primary space mode */
if (REAL_MODE(&(regs->psw))
|| !PRIMARY_SPACE_MODE(&(regs->psw)))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Special operation exception if subsystem linkage
control bit in CR5 is zero (when ASF is off)*/
if (!ASF_ENABLED(regs) && !(regs->CR_L(5) & LTD_SSLINK))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Save the primary ASN (CR4) and primary STD (CR1) */
oldpasn = regs->CR_LHL(4);
oldpstd = regs->CR(1);
/* Extract the PSW key mask from R1 register bits 0-15 */
pkm = regs->GR_LHH(r1);
/* Extract the ASN from R1 register bits 16-31 */
pasn = regs->GR_LHL(r1);
#ifdef FEATURE_TRACING
/* Build trace entry if ASN tracing is on */
if (regs->CR(12) & CR12_ASNTRACE)
newcr12 = ARCH_DEP(trace_pt) (pasn, regs->GR(r2), regs);
#endif /*FEATURE_TRACING*/
/* Determine instruction address, amode, and problem state */
#if defined(FEATURE_ESAME)
if (regs->psw.amode64)
{
/* In 64-bit address mode, extract instruction address from
R2 register bits 0-62, and leave address mode unchanged */
ia = regs->GR_G(r2) & 0xFFFFFFFFFFFFFFFEULL;
amode = regs->psw.amode;
}
else
#endif /*defined(FEATURE_ESAME)*/
{
/* In 31- or 24-bit mode, extract new amode from R2 bit 0 */
amode = (regs->GR_L(r2) & 0x80000000) ? 1 : 0;
/* Extract the instruction address from R2 bits 1-30 */
ia = regs->GR_L(r2) & 0x7FFFFFFE;
}
/* Extract the problem state bit from R2 register bit 31 */
prob = regs->GR_L(r2) & 0x00000001;
/* [5.5.3.1] Load the linkage table designation */
if (!ASF_ENABLED(regs))
{
/* Obtain the LTD from control register 5 */
ltd = regs->CR_L(5);
}
else
{
/* Obtain the primary ASTE origin from control register 5 */
pasteo = regs->CR_L(5) & CR5_PASTEO;
/* Convert the PASTE origin to an absolute address */
abs = APPLY_PREFIXING (pasteo, regs->PX);
/* Program check if PASTE is outside main storage */
if (abs >= regs->mainsize)
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Fetch primary ASTE words 3 and 6 from absolute storage
(note: the ASTE cannot cross a page boundary) */
#if !defined(FEATURE_ESAME)
aste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs);
#else /*defined(FEATURE_ESAME)*/
aste[6] = ARCH_DEP(fetch_fullword_absolute) (abs+24, regs);
#endif /*defined(FEATURE_ESAME)*/
/* Load LTD from primary ASTE word 3 or 6 */
ltd = ASTE_LT_DESIGNATOR(aste);
}
/* Special operation exception if subsystem linkage
control bit in linkage table designation is zero */
if ((ltd & LTD_SSLINK) == 0)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Privileged operation exception if in problem state and
problem bit indicates a change to supervisor state */
if (regs->psw.prob && 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) )
{
INVALIDATE_AIA(regs);
/* 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);
/* Perform primary address space authorization
using current authorization index */
ax = regs->CR_LHH(4);
if (ARCH_DEP(authorize_asn) (ax, aste, ATE_PRIMARY, regs))
{
regs->TEA = pasn;
ARCH_DEP(program_interrupt) (regs, PGM_PRIMARY_AUTHORITY_EXCEPTION);
}
/* Obtain new primary STD or ASCE from the ASTE */
pstd = ASTE_AS_DESIGNATOR(aste);
#ifdef FEATURE_SUBSPACE_GROUP
/* Perform subspace replacement on new PSTD */
pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, NULL, regs);
#endif /*FEATURE_SUBSPACE_GROUP*/
/* Space switch if either current PSTD or new PSTD
space-switch-event control bit is set to 1 */
if ((regs->CR(1) & SSEVENT_BIT) || (pstd & SSEVENT_BIT))
{
/* Indicate space-switch event required */
ssevent = 1;
}
else
{
ssevent = 2; /* maybe, if PER is pending */
}
/* Load new primary STD or ASCE into control register 1 */
regs->CR(1) = pstd;
/* Load new AX and PASN into control register 4 */
regs->CR_L(4) = (aste[1] & ASTE1_AX) | pasn;
/* Load new PASTEO or LTD into control register 5 */
regs->CR_L(5) = ASF_ENABLED(regs) ?
pasteo : ASTE_LT_DESIGNATOR(aste);
} /* end if(PT-ss) */
else
{
/* For PT-cp use current primary STD or ASCE */
pstd = regs->CR(1);
}
#ifdef FEATURE_TRACING
/* Update trace table address if ASN tracing is on */
if (regs->CR(12) & CR12_ASNTRACE)
regs->CR(12) = newcr12;
#endif /*FEATURE_TRACING*/
#if defined(FEATURE_PER)
if( EN_IC_PER_SB(regs)
#if defined(FEATURE_PER2)
&& ( !(regs->CR(9) & CR9_BAC)
|| PER_RANGE_CHECK(ia,regs->CR(10),regs->CR(11)) )
#endif /*defined(FEATURE_PER2)*/
)
ON_IC_PER_SB(regs);
#endif /*defined(FEATURE_PER)*/
/* Replace PSW amode, instruction address, and problem state bit */
regs->psw.amode = amode;
regs->psw.IA = ia;
regs->psw.prob = prob;
regs->psw.AMASK =
#if defined(FEATURE_ESAME)
regs->psw.amode64 ? AMASK64 :
#endif /*defined(FEATURE_ESAME)*/
regs->psw.amode ? AMASK31 : AMASK24;
/* AND control register 3 bits 0-15 with the supplied PKM value
and replace the SASN in CR3 bits 16-31 with new PASN */
regs->CR_LHH(3) &= pkm;
regs->CR_LHL(3) = pasn;
/* Set secondary STD or ASCE equal to new primary STD or ASCE */
regs->CR(7) = pstd;
/* 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);
}
#endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/
#if defined(FEATURE_ACCESS_REGISTERS)
/*-------------------------------------------------------------------*/
/* B248 PALB - Purge ALB [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(purge_accesslist_lookaside_buffer)
{
int r1, r2; /* Register values (unused) */
RRE(inst, execflag, regs, r1, r2);
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
/* This instruction is executed as a no-operation in XC mode */
if(regs->sie_state && (regs->siebk->mx & SIE_MX_XC))
return;
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
PRIV_CHECK(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_PXLB))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Purge the ART lookaside buffer for this CPU */
ARCH_DEP(purge_alb) (regs);
}
#endif /*defined(FEATURE_ACCESS_REGISTERS)*/
/*-------------------------------------------------------------------*/
/* B20D PTLB - Purge TLB [S] */
/*-------------------------------------------------------------------*/
DEF_INST(purge_translation_lookaside_buffer)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
S(inst, execflag, regs, b2, effective_addr2);
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
/* This instruction is executed as a no-operation in XC mode */
if(regs->sie_state && (regs->siebk->mx & SIE_MX_XC))
return;
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
PRIV_CHECK(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_PXLB))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Purge the translation lookaside buffer for this CPU */
ARCH_DEP(purge_tlb) (regs);
}
#if defined(FEATURE_BASIC_STORAGE_KEYS)
/*-------------------------------------------------------------------*/
/* B213 RRB - Reset Reference Bit [S] */
/*-------------------------------------------------------------------*/
DEF_INST(reset_reference_bit)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
RADR n; /* Absolute storage addr */
BYTE storkey; /* Storage key */
S(inst, execflag, regs, b2, effective_addr2);
#if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE)
if(
#if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS)
regs->sie_state &&
#endif
!(regs->CR(0) & CR0_STORKEY_4K) )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#endif
PRIV_CHECK(regs);
/* Load 2K block real address from operand address */
n = effective_addr2 & 0x00FFF800;
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state)
{
if(regs->siebk->ic[2] & SIE_IC2_RRBE)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
if(!regs->sie_pref)
{
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
&& (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY))
{
SIE_TRANSLATE(&n, ACCTYPE_SIE, regs);
#if !defined(_FEATURE_2K_STORAGE_KEYS)
storkey = STORAGE_KEY(n);
#else
storkey = STORAGE_KEY1(n) | STORAGE_KEY2(n);
#endif
/* Reset the reference bit in the storage key */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= ~(STORKEY_REF);
#else
STORAGE_KEY1(n) &= ~(STORKEY_REF);
STORAGE_KEY2(n) &= ~(STORKEY_REF);
#endif
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
BYTE rcpkey, realkey;
RADR ra;
RADR rcpa;
U16 xcode;
int private,
protect,
stid;
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
{
/* guest absolute to host PTE addr */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private,
&protect, &stid))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
/* Convert real address to absolute address */
rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX);
/* The reference and change byte is located directly
beyond the page table and is located at offset 1 in
the entry. S/370 mode cannot be emulated in ESAME
mode, so no provision is made for ESAME mode tables */
rcpa += 1025;
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
/* Obtain address of the RCP area from the state desc */
rcpa = regs->sie_rcpo &= 0x7FFFF000;
/* frame index as byte offset to 4K keys in RCP area */
rcpa += n >> 12;
/* host primary to host absolute */
rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, 0);
}
/* fetch the RCP key */
rcpkey = sysblk.mainstor[rcpa];
STORAGE_KEY(rcpa) |= STORKEY_REF;
if (!SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &ra, &xcode, &private,
&protect, &stid))
{
ra = APPLY_PREFIXING(ra, regs->hostregs->PX);
#if !defined(_FEATURE_2K_STORAGE_KEYS)
realkey = STORAGE_KEY(ra)
#else
realkey = (STORAGE_KEY1(ra) | STORAGE_KEY2(ra))
#endif
& (STORKEY_REF | STORKEY_CHANGE);
/* Reset reference and change bits in storage key */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(ra) &= ~(STORKEY_REF | STORKEY_CHANGE);
#else
STORAGE_KEY1(ra) &= ~(STORKEY_REF | STORKEY_CHANGE);
STORAGE_KEY2(ra) &= ~(STORKEY_REF | STORKEY_CHANGE);
#endif
}
else
realkey = 0;
/* The storage key is obtained by logical or
or the real and guest RC bits */
storkey = realkey | (rcpkey & (STORKEY_REF | STORKEY_CHANGE));
/* or with host set */
rcpkey |= realkey << 4;
/* Put storage key in guest set */
rcpkey |= storkey;
/* reset the reference bit */
rcpkey &= ~(STORKEY_REF);
sysblk.mainstor[rcpa] = rcpkey;
STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE);
}
}
else /* regs->sie_perf */
{
#if !defined(_FEATURE_2K_STORAGE_KEYS)
storkey = STORAGE_KEY(n);
#else
storkey = STORAGE_KEY1(n) | STORAGE_KEY2(n);
#endif
/* Reset the reference bit in the storage key */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= ~(STORKEY_REF);
#else
STORAGE_KEY1(n) &= ~(STORKEY_REF);
STORAGE_KEY2(n) &= ~(STORKEY_REF);
#endif
}
}
else
#endif /*defined(_FEATURE_SIE)*/
{
#if !defined(_FEATURE_2K_STORAGE_KEYS)
storkey = STORAGE_KEY(n);
#else
storkey = STORAGE_KEY1(n) | STORAGE_KEY2(n);
#endif
/* Reset the reference bit in the storage key */
#if defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= ~(STORKEY_REF);
#else
STORAGE_KEY1(n) &= ~(STORKEY_REF);
STORAGE_KEY2(n) &= ~(STORKEY_REF);
#endif
}
/* Set the condition code according to the original state
of the reference and change bits in the storage key */
regs->psw.cc =
((storkey & STORKEY_REF) ? 2 : 0)
| ((storkey & STORKEY_CHANGE) ? 1 : 0);
}
#endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/
#if defined(FEATURE_EXTENDED_STORAGE_KEYS)
/*-------------------------------------------------------------------*/
/* B22A RRBE - Reset Reference Bit Extended [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(reset_reference_bit_extended)
{
int r1, r2; /* Register values */
RADR n; /* Abs frame addr stor key */
BYTE storkey; /* Storage key */
RRE(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
/* Load 4K block address from R2 register */
n = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state)
{
if(regs->siebk->ic[2] & SIE_IC2_RRBE)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
if(!regs->sie_pref)
{
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY))
{
SIE_TRANSLATE(&n, ACCTYPE_SIE, regs);
#if !defined(_FEATURE_2K_STORAGE_KEYS)
storkey = STORAGE_KEY(n);
#else
storkey = STORAGE_KEY1(n)
| (STORAGE_KEY2(n) & (STORKEY_REF|STORKEY_CHANGE))
#endif
;
/* Reset the reference bit in the storage key */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= ~(STORKEY_REF);
#else
STORAGE_KEY1(n) &= ~(STORKEY_REF);
STORAGE_KEY2(n) &= ~(STORKEY_REF);
#endif
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
BYTE rcpkey, realkey;
RADR ra;
RADR rcpa;
U16 xcode;
int private,
protect,
stid;
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
)
{
/* guest absolute to host PTE addr */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private,
&protect, &stid))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
/* Convert real address to absolute address */
rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX);
/* For ESA/390 the RCP byte entry is at offset 1 in a
four byte entry directly beyond the page table,
for ESAME mode, this entry is eight bytes long */
rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025;
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
if(regs->siebk->mx & SIE_MX_XC)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
/* Obtain address of the RCP area from the state desc */
rcpa = regs->sie_rcpo &= 0x7FFFF000;
/* frame index as byte offset to 4K keys in RCP area */
rcpa += n >> 12;
/* host primary to host absolute */
rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, 0);
}
/* fetch the RCP key */
rcpkey = sysblk.mainstor[rcpa];
STORAGE_KEY(rcpa) |= STORKEY_REF;
if (!SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &ra, &xcode, &private,
&protect, &stid))
{
ra = APPLY_PREFIXING(ra, regs->hostregs->PX);
#if !defined(_FEATURE_2K_STORAGE_KEYS)
realkey = STORAGE_KEY(ra) & (STORKEY_REF | STORKEY_CHANGE);
#else
realkey = (STORAGE_KEY1(ra) | STORAGE_KEY2(ra))
& (STORKEY_REF | STORKEY_CHANGE);
#endif
/* Reset the reference and change bits in
the real machine storage key */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(ra) &= ~(STORKEY_REF | STORKEY_CHANGE);
#else
STORAGE_KEY1(ra) &= ~(STORKEY_REF | STORKEY_CHANGE);
STORAGE_KEY2(ra) &= ~(STORKEY_REF | STORKEY_CHANGE);
#endif
}
else
realkey = 0;
/* The storage key is obtained by logical or
or the real and guest RC bits */
storkey = realkey | (rcpkey & (STORKEY_REF | STORKEY_CHANGE));
/* or with host set */
rcpkey |= realkey << 4;
/* Put storage key in guest set */
rcpkey |= storkey;
/* reset the reference bit */
rcpkey &= ~(STORKEY_REF);
sysblk.mainstor[rcpa] = rcpkey;
STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE);
}
}
else
{
#if !defined(_FEATURE_2K_STORAGE_KEYS)
storkey = STORAGE_KEY(n);
#else
storkey = STORAGE_KEY1(n)
| (STORAGE_KEY2(n) & (STORKEY_REF|STORKEY_CHANGE))
#endif
;
/* Reset the reference bit in the storage key */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= ~(STORKEY_REF);
#else
STORAGE_KEY1(n) &= ~(STORKEY_REF);
STORAGE_KEY2(n) &= ~(STORKEY_REF);
#endif
}
}
else
#endif /*defined(_FEATURE_SIE)*/
{
#if !defined(_FEATURE_2K_STORAGE_KEYS)
storkey = STORAGE_KEY(n);
#else
storkey = STORAGE_KEY1(n)
| (STORAGE_KEY2(n) & (STORKEY_REF|STORKEY_CHANGE))
#endif
;
/* Reset the reference bit in the storage key */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= ~(STORKEY_REF);
#else
STORAGE_KEY1(n) &= ~(STORKEY_REF);
STORAGE_KEY2(n) &= ~(STORKEY_REF);
#endif
}
/* Set the condition code according to the original state
of the reference and change bits in the storage key */
regs->psw.cc =
((storkey & STORKEY_REF) ? 2 : 0)
| ((storkey & STORKEY_CHANGE) ? 1 : 0);
} /* 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_x)
{
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, execflag, regs, b2, effective_addr2);
INVALIDATE_AEA_ALL(regs);
if(inst[1] == 0x19)
{
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
}
/* Isolate bits 20-23 of effective address */
mode = (effective_addr2 & 0x00000F00) >> 8;
/* Special operation exception if DAT is off or
secondary-space control bit is zero */
if ((REAL_MODE(&(regs->psw))
|| (regs->CR(0) & CR0_SEC_SPACE) == 0)
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
&& !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC))
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Privileged operation exception if setting home-space
mode while in problem state */
if (mode == 3 && regs->psw.prob)
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 */
|| (regs->sie_state
&& (regs->siebk->mx & SIE_MX_XC)
&& (mode == 1 || mode == 3) )
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
/* Save the current address-space control bits */
oldmode = (regs->psw.armode << 1) | (regs->psw.space);
/* Reset the address-space control bits in the PSW */
regs->psw.space = mode & 1;
regs->psw.armode = mode >> 1;
INVALIDATE_AIA(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_PERINT(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(inst[1] == 0x19)
{
/* 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 */
int cpu;
S(inst, execflag, regs, b2, effective_addr2);
SIE_MODE_XC_OPEX(regs);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
DW_CHECK(effective_addr2, regs);
/* Fetch new TOD clock value from operand address */
dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs);
/* Obtain the TOD clock update lock */
obtain_lock (&sysblk.todlock);
/* Compute the new TOD clock offset in hercules clock units */
sysblk.todoffset = (dreg >> 8) - sysblk.todclk;
/* Update the TOD clock of all CPU's in the configuration
as we simulate 1 shared TOD clock, and do not support the
TOD clock sync check */
for(cpu = 0; cpu < MAX_CPU_ENGINES; cpu++)
sysblk.regs[cpu].todoffset = sysblk.todoffset;
/* Release the TOD clock update lock */
release_lock (&sysblk.todlock);
// /*debug*/logmsg("Set TOD clock=%16.16llX\n", dreg);
/* Return condition code zero */
regs->psw.cc = 0;
}
/*-------------------------------------------------------------------*/
/* 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, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
DW_CHECK(effective_addr2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SCKC))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Fetch clock comparator value from operand location */
dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs )
& 0xFFFFFFFFFFFFF000ULL;
// /*debug*/logmsg("Set clock comparator=%16.16llX\n", dreg);
/* Obtain the TOD clock update lock */
obtain_lock (&sysblk.todlock);
/* Update the clock comparator and set epoch to zero */
regs->clkc = dreg >> 8;
/* reset the clock comparator pending flag according to
the setting of the tod clock */
update_TOD_clock();
/* Release the TOD clock update lock */
release_lock (&sysblk.todlock);
RETURN_INTCHECK(regs);
}
#if defined(FEATURE_EXTENDED_TOD_CLOCK)
/*-------------------------------------------------------------------*/
/* 0107 SCKPF - Set Clock Programmable Field [E] */
/*-------------------------------------------------------------------*/
DEF_INST(set_clock_programmable_field)
{
E(inst, execflag, 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 */
U64 dreg; /* Timer value */
S(inst, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
DW_CHECK(effective_addr2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SPT))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Fetch the CPU timer value from operand location */
dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs )
& 0xFFFFFFFFFFFFF000ULL;
/* Obtain the TOD clock update lock */
obtain_lock (&sysblk.todlock);
/* Update the CPU timer */
regs->ptimer = dreg;
/* reset the cpu timer pending flag according to its value */
update_TOD_clock();
/* Release the TOD clock update lock */
release_lock (&sysblk.todlock);
// /*debug*/logmsg("Set CPU timer=%16.16llX\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, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
FW_CHECK(effective_addr2, regs);
/* Perform serialization before fetching the operand */
PERFORM_SERIALIZATION (regs);
/* Load new prefix value from operand address */
n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs );
/* Isolate bits 1-19 for ESA/390 or 1-18 for ESAME of new prefix value */
n &= PX_MASK;
/* Program check if prefix is invalid absolute address */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Load new value into prefix register */
regs->PX = n;
/* Invalidate the ALB and TLB */
ARCH_DEP(purge_tlb) (regs);
#if defined(FEATURE_ACCESS_REGISTERS)
ARCH_DEP(purge_alb) (regs);
#endif /*defined(FEATURE_ACCESS_REGISTERS)*/
/* Perform serialization after completing the operation */
PERFORM_SERIALIZATION (regs);
}
/*-------------------------------------------------------------------*/
/* B20A SPKA - Set PSW Key from Address [S] */
/*-------------------------------------------------------------------*/
DEF_INST(set_psw_key_from_address)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
int n; /* Storage key workarea */
S(inst, execflag, regs, b2, effective_addr2);
/* 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 ( regs->psw.prob
&& ((regs->CR(3) << (n >> 4)) & 0x80000000) == 0 )
ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
/* Set PSW key */
regs->psw.pkey = n;
}
#if defined(FEATURE_DUAL_ADDRESS_SPACE)
/*-------------------------------------------------------------------*/
/* B225 SSAR - Set Secondary ASN [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(set_secondary_asn)
{
int r1, r2; /* Register numbers */
U16 sasn; /* New Secondary ASN */
RADR sstd; /* Secondary STD */
U32 sasteo; /* Secondary ASTE origin */
U32 aste[16]; /* ASN second table entry */
U16 xcode; /* Exception code */
U16 ax; /* Authorization index */
#ifdef FEATURE_TRACING
CREG newcr12 = 0; /* CR12 upon completion */
#endif /*FEATURE_TRACING*/
RRE(inst, execflag, regs, r1, r2);
SIE_MODE_XC_OPEX(regs);
INVALIDATE_AEA_ALL(regs);
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
/* Special operation exception if ASN translation control
(bit 12 of control register 14) is zero or DAT is off */
if ((regs->CR(14) & CR14_ASN_TRAN) == 0
|| REAL_MODE(&(regs->psw)))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Load the new ASN from R1 register bits 16-31 */
sasn = regs->GR_LHL(r1);
#ifdef FEATURE_TRACING
/* Form trace entry if ASN tracing is on */
if (regs->CR(12) & CR12_ASNTRACE)
newcr12 = ARCH_DEP(trace_ssar) (sasn, regs);
#endif /*FEATURE_TRACING*/
/* Test for SSAR to current primary */
if ( sasn == regs->CR_LHL(4) )
{
/* Set new secondary STD equal to primary STD */
sstd = regs->CR(1);
} /* end if(SSAR-cp) */
else
{ /* SSAR 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);
/* 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);
#ifdef FEATURE_SUBSPACE_GROUP
/* Perform subspace replacement on new SSTD */
sstd = ARCH_DEP(subspace_replace) (sstd, sasteo, NULL, regs);
#endif /*FEATURE_SUBSPACE_GROUP*/
} /* end if(SSAR-ss) */
#ifdef FEATURE_TRACING
/* Update trace table address if ASN tracing is on */
if (regs->CR(12) & CR12_ASNTRACE)
regs->CR(12) = newcr12;
#endif /*FEATURE_TRACING*/
/* Load the new secondary ASN into control register 3 */
regs->CR_LHL(3) = sasn;
/* Load the new secondary STD into control register 7 */
regs->CR(7) = sstd;
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
}
#endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/
#if defined(FEATURE_BASIC_STORAGE_KEYS)
/*-------------------------------------------------------------------*/
/* 08 SSK - Set Storage Key [RR] */
/*-------------------------------------------------------------------*/
DEF_INST(set_storage_key)
{
int r1, r2; /* Values of R fields */
RADR n; /* Absolute storage addr */
RR(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
#if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE)
if(
#if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS)
regs->sie_state &&
#endif
!(regs->CR(0) & CR0_STORKEY_4K) )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#endif
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
/* Program check if R2 bits 28-31 are not zeroes */
if ( regs->GR_L(r2) & 0x0000000F )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
/* Load 2K block address from R2 register */
n = regs->GR_L(r2) & 0x00FFF800;
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state)
{
if(regs->siebk->ic[2] & SIE_IC2_SSKE)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
if(!regs->sie_pref)
{
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
&& (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY))
{ SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); }
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
U16 xcode;
int private,
protect,
stid,
sr;
BYTE realkey,
rcpkey;
RADR rcpa;
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
{
/* guest absolute to host PTE addr */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private,
&protect, &stid))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
/* Convert real address to absolute address */
rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX);
/* The reference and change byte is located directly
beyond the page table and is located at offset 1 in
the entry. S/370 mode cannot be emulated in ESAME
mode, so no provision is made for ESAME mode tables */
rcpa += 1025;
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
/* Obtain address of the RCP area from the state desc */
rcpa = regs->sie_rcpo &= 0x7FFFF000;
/* frame index as byte offset to 4K keys in RCP area */
rcpa += n >> 12;
/* host primary to host absolute */
rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, 0);
}
/* guest absolute to host real */
sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private,
&protect, &stid);
if(sr
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
&& !(regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(sr)
realkey = 0;
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
/* host real to host absolute */
n = APPLY_PREFIXING(n, regs->hostregs->PX);
realkey =
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n)
#else
(STORAGE_KEY1(n) | STORAGE_KEY2(n))
#endif
& (STORKEY_REF | STORKEY_CHANGE);
}
/* fetch the RCP key */
rcpkey = sysblk.mainstor[rcpa];
STORAGE_KEY(rcpa) |= STORKEY_REF;
/* or with host set */
rcpkey |= realkey << 4;
/* or new settings with guest set */
rcpkey &= ~(STORKEY_REF | STORKEY_CHANGE);
rcpkey |= regs->GR_L(r1) & (STORKEY_REF | STORKEY_CHANGE);
sysblk.mainstor[rcpa] = rcpkey;
STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE);
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
/* Insert key in new storage key */
if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
sysblk.mainstor[rcpa-1] = regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
if(!sr)
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= STORKEY_BADFRM;
STORAGE_KEY(n) |= regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
#else
STORAGE_KEY1(n) &= STORKEY_BADFRM;
STORAGE_KEY1(n) |= regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
STORAGE_KEY2(n) &= STORKEY_BADFRM;
STORAGE_KEY2(n) |= regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
#endif
}
}
}
else
{
/* Update the storage key from R1 register bits 24-30 */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= STORKEY_BADFRM;
STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#else
STORAGE_KEY1(n) &= STORKEY_BADFRM;
STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
STORAGE_KEY2(n) &= STORKEY_BADFRM;
STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#endif
}
}
else
#endif /*defined(_FEATURE_SIE)*/
{
/* Update the storage key from R1 register bits 24-30 */
#if defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= STORKEY_BADFRM;
STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#else
STORAGE_KEY1(n) &= STORKEY_BADFRM;
STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
STORAGE_KEY2(n) &= STORKEY_BADFRM;
STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#endif
}
// /*debug*/logmsg("SSK storage block %8.8X key %2.2X\n",
// /*debug*/ regs->GR_L(r2), regs->GR_LHLCL(r1) & 0xFE);
}
#endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/
#if defined(FEATURE_EXTENDED_STORAGE_KEYS)
/*-------------------------------------------------------------------*/
/* B22B SSKE - Set Storage Key extended [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(set_storage_key_extended)
{
int r1, r2; /* Register numbers */
RADR n; /* Abs frame addr stor key */
RRE(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
/* Load 4K block address from R2 register */
n = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state)
{
if(regs->siebk->ic[2] & SIE_IC2_SSKE)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
if(!regs->sie_pref)
{
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY))
{ SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); }
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
U16 xcode;
int private,
protect,
stid,
sr;
BYTE realkey,
rcpkey;
RADR rcpa;
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
)
{
/* guest absolute to host PTE addr */
if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private,
&protect, &stid))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
/* Convert real address to absolute address */
rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX);
/* For ESA/390 the RCP byte entry is at offset 1 in a
four byte entry directly beyond the page table,
for ESAME mode, this entry is eight bytes long */
rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025;
}
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
if(regs->siebk->mx & SIE_MX_XC)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
/* Obtain address of the RCP area from the state desc */
rcpa = regs->sie_rcpo &= 0x7FFFF000;
/* frame index as byte offset to 4K keys in RCP area */
rcpa += n >> 12;
/* host primary to host absolute */
rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, 0);
}
/* guest absolute to host real */
sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private,
&protect, &stid);
if(sr
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
&& !((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
)
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
)
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
if(sr)
realkey = 0;
else
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
/* host real to host absolute */
n = APPLY_PREFIXING(n, regs->hostregs->PX);
realkey =
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n)
#else
(STORAGE_KEY1(n) | STORAGE_KEY2(n))
#endif
& (STORKEY_REF | STORKEY_CHANGE);
}
/* fetch the RCP key */
rcpkey = sysblk.mainstor[rcpa];
STORAGE_KEY(rcpa) |= STORKEY_REF;
/* or with host set */
rcpkey |= realkey << 4;
/* insert new settings of the guest set */
rcpkey &= ~(STORKEY_REF | STORKEY_CHANGE);
rcpkey |= regs->GR_LHLCL(r1) & (STORKEY_REF | STORKEY_CHANGE);
sysblk.mainstor[rcpa] = rcpkey;
STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE);
#if defined(_FEATURE_STORAGE_KEY_ASSIST)
/* Insert key in new storage key */
if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA)
#if defined(_FEATURE_ZSIE)
|| (regs->hostregs->arch_mode == ARCH_900)
#endif /*defined(_FEATURE_ZSIE)*/
)
sysblk.mainstor[rcpa-1] = regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
if(!sr)
#endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/
{
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= STORKEY_BADFRM;
STORAGE_KEY(n) |= regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
#else
STORAGE_KEY1(n) &= STORKEY_BADFRM;
STORAGE_KEY1(n) |= regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
STORAGE_KEY2(n) &= STORKEY_BADFRM;
STORAGE_KEY2(n) |= regs->GR_LHLCL(r1)
& (STORKEY_KEY | STORKEY_FETCH);
#endif
}
}
}
else
{
/* Update the storage key from R1 register bits 24-30 */
#if !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= STORKEY_BADFRM;
STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#else
STORAGE_KEY1(n) &= STORKEY_BADFRM;
STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
STORAGE_KEY2(n) &= STORKEY_BADFRM;
STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#endif
}
}
else
#endif /*defined(_FEATURE_SIE)*/
{
/* Update the storage key from R1 register bits 24-30 */
#if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS)
STORAGE_KEY(n) &= STORKEY_BADFRM;
STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#else
STORAGE_KEY1(n) &= STORKEY_BADFRM;
STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
STORAGE_KEY2(n) &= STORKEY_BADFRM;
STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM);
#endif
}
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
}
#endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/
/*-------------------------------------------------------------------*/
/* 80 SSM - Set System Mask [S] */
/*-------------------------------------------------------------------*/
DEF_INST(set_system_mask)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
#if defined(OPTION_REDUCED_INVAL)
int realmode;
int space;
int armode;
#endif
S(inst, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
#if defined(OPTION_REDUCED_INVAL)
realmode = REAL_MODE(&regs->psw);
armode = (regs->psw.armode == 1);
space = (regs->psw.space == 1);
#endif
/* 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 */
&& !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC))
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_SSM))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Load new system mask value from operand address */
regs->psw.sysmask = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs );
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
/* DAT must be off in XC mode */
if(regs->sie_state
&& (regs->siebk->mx & SIE_MX_XC)
&& (regs->psw.sysmask & PSW_DATMODE) )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
/* For ECMODE, bits 0 and 2-4 of system mask must be zero */
if (
#if defined(FEATURE_BCMODE)
regs->psw.ecmode &&
#endif /*defined(FEATURE_BCMODE)*/
(regs->psw.sysmask & 0xB8) != 0)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
SET_IC_EXTERNAL_MASK(regs);
SET_IC_MCK_MASK(regs);
SET_IC_IO_MASK(regs);
SET_IC_PER_MASK(regs);
INVALIDATE_AIA(regs);
#if defined(OPTION_REDUCED_INVAL)
if ((realmode != REAL_MODE(&regs->psw)) ||
(armode != (regs->psw.armode == 1)) ||
(space != (regs->psw.space == 1))
#if defined(FEATURE_PER)
|| PER_MODE(regs)
#endif /*defined(FEATURE_PER)*/
)
INVALIDATE_AEA_ALL(regs);
#else
INVALIDATE_AEA_ALL(regs);
#endif
RETURN_INTCHECK(regs);
}
/*-------------------------------------------------------------------*/
/* AE SIGP - Signal Processor [RS] */
/*-------------------------------------------------------------------*/
DEF_INST(signal_procesor)
{
int r1, r3; /* Register numbers */
int b2; /* effective address base */
VADR effective_addr2; /* effective address */
REGS *tregs; /* -> Target CPU registers */
GREG parm; /* Signal parameter */
GREG status = 0; /* Signal status */
RADR abs; /* Absolute address */
U16 cpad; /* Target CPU address */
BYTE order; /* SIGP order code */
#if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS)
int cpu; /* cpu number */
int set_arch = 0; /* Need to switch mode */
#endif /*defined(_900) || defined(FEATURE_ESAME)*/
static char *ordername[] = { "Unassigned",
/* SIGP_SENSE */ "Sense",
/* SIGP_EXTCALL */ "External call",
/* SIGP_EMERGENCY */ "Emergency signal",
/* SIGP_START */ "Start",
/* SIGP_STOP */ "Stop",
/* SIGP_RESTART */ "Restart",
/* SIGP_IPR */ "Initial program reset",
/* SIGP_PR */ "Program reset",
/* SIGP_STOPSTORE */ "Stop and store status",
/* SIGP_IMPL */ "Initial microprogram load",
/* SIGP_INITRESET */ "Initial CPU reset",
/* SIGP_RESET */ "CPU reset",
/* SIGP_SETPREFIX */ "Set prefix",
/* SIGP_STORE */ "Store status",
/* 0x0F */ "Unassigned",
/* 0x10 */ "Unassigned",
/* SIGP_STOREX */ "Store extended status at address",
/* SIGP_SETARCH */ "Set Architecture Mode" };
RS(inst, execflag, regs, r1, r3, b2, effective_addr2);
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);
/* Return condition code 3 if target CPU does not exist */
#ifdef _FEATURE_CPU_RECONFIG
if (cpad >= MAX_CPU_ENGINES)
#else /*!_FEATURE_CPU_RECONFIG*/
if (cpad >= sysblk.numcpu)
#endif /*!_FEATURE_CPU_RECONFIG*/
{
regs->psw.cc = 3;
return;
}
/* Point to the target CPU */
tregs = sysblk.regs + cpad;
/* Trace SIGP unless Sense, External Call, Emergency Signal,
or the target CPU is configured offline */
if (order > LOG_SIGPORDER || !tregs->cpuonline)
#if !defined(FEATURE_ESAME)
logmsg ("CPU%4.4X: SIGP CPU%4.4X %s PARM %8.8X\n",
regs->cpuad, cpad,
order > MAX_SIGPORDER ? ordername[0] : ordername[order],
parm);
#else /*defined(FEATURE_ESAME)*/
logmsg ("CPU%4.4X: SIGP CPU%4.4X %s PARM %16.16llX\n",
regs->cpuad, cpad,
order > MAX_SIGPORDER ? ordername[0] : ordername[order],
(long long)parm);
#endif /*defined(FEATURE_ESAME)*/
/* [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;
return;
}
/* Obtain the interrupt lock */
obtain_lock(&sysblk.intlock);
/* If the cpu is not part of the configuration then return cc3
Initial CPU reset may IML a processor that is currently not
part of the configuration, ie configure the cpu implicitly
online */
if (order != SIGP_INITRESET
#if defined(FEATURE_S370_CHANNEL)
&& order != SIGP_IMPL
#endif /*defined(FEATURE_S370_CHANNEL)*/
&& !tregs->cpuonline)
{
release_lock(&sysblk.sigplock);
release_lock(&sysblk.intlock);
regs->psw.cc = 3;
return;
}
/* 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->cpustate == CPUSTATE_STOPPING
|| IS_IC_RESTART(tregs)))
{
release_lock(&sysblk.sigplock);
release_lock(&sysblk.intlock);
regs->psw.cc = 2;
return;
}
/* If the CPU thread is still starting, ie CPU is still performing
the IML process then relect an operator intervening status
to the caller */
if(tregs->cpustate == CPUSTATE_STARTING)
status |= SIGP_STATUS_OPERATOR_INTERVENING;
else
/* 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;
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;
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;
OFF_IC_CPU_NOT_STARTED(tregs);
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_CPU_NOT_STARTED(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_CPU_NOT_STARTED(tregs);
break;
#if defined(FEATURE_S370_CHANNEL)
case SIGP_IMPL:
case SIGP_IPR:
channelset_reset(tregs);
/* fallthrough*/
#endif /* defined(FEATURE_S370_CHANNEL) */
case SIGP_INITRESET:
if(tregs->cpuonline)
{
/* Signal initial CPU reset function */
tregs->sigpireset = 1;
tregs->cpustate = CPUSTATE_STOPPING;
ON_IC_CPU_NOT_STARTED(tregs);
}
else
configure_cpu(tregs);
break;
#if defined(FEATURE_S370_CHANNEL)
case SIGP_PR:
channelset_reset(tregs);
/* fallthrough*/
#endif /* defined(FEATURE_S370_CHANNEL) */
case SIGP_RESET:
/* Signal CPU reset function */
tregs->sigpreset = 1;
tregs->cpustate = CPUSTATE_STOPPING;
ON_IC_CPU_NOT_STARTED(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->mainsize)
{
status |= SIGP_STATUS_INVALID_PARAMETER;
break;
}
/* Load new value into prefix register of target CPU */
tregs->PX = abs;
/* Invalidate the ALB and TLB of the target CPU */
ARCH_DEP(purge_tlb) (tregs);
#if defined(FEATURE_ACCESS_REGISTERS)
ARCH_DEP(purge_alb) (tregs);
#endif /*defined(FEATURE_ACCESS_REGISTERS)*/
/* Perform serialization and checkpoint-sync on target CPU */
// perform_serialization (tregs);
// perform_chkpt_sync (tregs);
break;
case SIGP_STORE:
/* Test for checkstop state */
if(tregs->checkstop)
{
status |= SIGP_STATUS_CHECK_STOP;
break;
}
/* Exit with operator intervening if the status is
stopping, such that a retry can be attempted */
if(tregs->cpustate == CPUSTATE_STOPPING)
{
status |= SIGP_STATUS_OPERATOR_INTERVENING;
break;
}
/* Exit with status bit 22 set if CPU is not stopped */
if (tregs->cpustate != CPUSTATE_STOPPED)
{
status |= SIGP_STATUS_INCORRECT_STATE;
break;
}
/* Obtain status address from parameter register bits 1-22 */
abs = parm & 0x7FFFFE00;
/* Exit with status bit 23 set if status address invalid */
if (abs >= regs->mainsize)
{
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;
case SIGP_STOREX:
/* Test for checkstop state */
if(tregs->checkstop)
{
status |= SIGP_STATUS_CHECK_STOP;
break;
}
/*INCOMPLETE*/
break;
#if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS)
case SIGP_SETARCH:
/* CPU must have ESAME support */
if(!sysblk.arch_z900)
status = SIGP_STATUS_INVALID_ORDER;
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
#ifdef _FEATURE_CPU_RECONFIG
for (cpu = 0; cpu < MAX_CPU_ENGINES; cpu++)
#else /*!_FEATURE_CPU_RECONFIG*/
for (cpu = 0; cpu < sysblk.numcpu; cpu++)
#endif /*!_FEATURE_CPU_RECONFIG*/
if(sysblk.regs[cpu].cpuonline
&& sysblk.regs[cpu].cpustate != CPUSTATE_STOPPED
&& sysblk.regs[cpu].cpuad != regs->cpuad)
status |= SIGP_STATUS_INCORRECT_STATE;
if(!status)
switch(parm & 0xFF) {
case 0:
if(sysblk.arch_mode == ARCH_390)
status = SIGP_STATUS_INVALID_ORDER;
sysblk.arch_mode = ARCH_390;
regs->psw.notesame = 1;
regs->PX_L &= 0x7FFFE000;
set_arch = 1;
break;
case 1:
if(sysblk.arch_mode == ARCH_900)
status = SIGP_STATUS_INVALID_ORDER;
sysblk.arch_mode = ARCH_900;
regs->psw.notesame = 0;
regs->psw.IA_H = 0;
regs->PX_G &= 0x7FFFE000;
set_arch = 1;
break;
#if defined(FEATURE_HERCULES_DIAGCALLS)
case 37:
if(sysblk.arch_mode == ARCH_370)
status = SIGP_STATUS_INVALID_ORDER;
sysblk.arch_mode = ARCH_370;
set_arch = 1;
break;
#endif /*defined(FEATURE_HERCULES_DIAGCALLS)*/
default:
status |= SIGP_STATUS_INVALID_PARAMETER;
}
#if defined(OPTION_FISHIO)
ios_arch_mode = sysblk.arch_mode;
#endif // defined(OPTION_FISHIO)
/* Invalidate the ALB and TLB */
ARCH_DEP(purge_tlb) (regs);
#if defined(FEATURE_ACCESS_REGISTERS)
ARCH_DEP(purge_alb) (tregs);
#endif /*defined(FEATURE_ACCESS_REGISTERS)*/
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
break;
#endif /*defined(_900) || defined(FEATURE_ESAME)*/
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 */
WAKEUP_CPU (tregs->cpuad);
/* Release the interrupt lock */
release_lock (&sysblk.intlock);
/* 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;
/* Perform serialization after completing operation */
PERFORM_SERIALIZATION (regs);
#if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS)
if(set_arch)
longjmp(regs->archjmp, 0);
#endif /*defined(_900) || defined(FEATURE_ESAME)*/
RETURN_INTCHECK(regs);
}
/*-------------------------------------------------------------------*/
/* B207 STCKC - Store Clock Comparator [S] */
/*-------------------------------------------------------------------*/
DEF_INST(store_clock_comparator)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
U64 dreg; /* Clock value */
S(inst, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
DW_CHECK(effective_addr2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SCKC))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Obtain the TOD clock update lock */
obtain_lock (&sysblk.todlock);
/* Save clock comparator value */
dreg = regs->clkc;
/* Release the TOD clock update lock */
release_lock (&sysblk.todlock);
/* Obtain the interrupt lock */
obtain_lock (&sysblk.intlock);
/* reset the clock comparator pending flag according to
the setting of the tod clock */
if( (sysblk.todclk + regs->todoffset) > 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) )
{
regs->psw.IA -= regs->psw.ilc;
regs->psw.IA &= ADDRESS_MAXWRAP(regs);
release_lock (&sysblk.intlock);
RETURN_INTCHECK(regs);
}
}
else
OFF_IC_CLKC(regs);
/* Release the interrupt lock */
release_lock (&sysblk.intlock);
/* Shift out the epoch */
dreg <<= 8;
/* Store clock comparator value at operand location */
ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs );
// /*debug*/logmsg("Store clock comparator=%16.16llX\n", dreg);
RETURN_INTCHECK(regs);
}
/*-------------------------------------------------------------------*/
/* B6 STCTL - Store Control [RS] */
/*-------------------------------------------------------------------*/
DEF_INST(store_control)
{
int r1, r3; /* Register numbers */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
int i, d; /* Integer work areas */
BYTE rwork[64]; /* Register work areas */
RS(inst, execflag, regs, r1, r3, b2, effective_addr2);
PRIV_CHECK(regs);
FW_CHECK(effective_addr2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_STCTL))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Copy control registers into work area */
for ( i = r1, d = 0; ; )
{
/* Copy control register bits 32-63 to work area */
STORE_FW(rwork + d, regs->CR_L(i)); d += 4;
/* Instruction is complete when r3 register is done */
if ( i == r3 ) break;
/* Update register number, wrapping from 15 to 0 */
i++; i &= 15;
}
/* Store control register contents at operand address */
ARCH_DEP(vstorec) ( rwork, d-1, effective_addr2, b2, 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, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
ODD_CHECK(effective_addr2, regs);
/* Store CPU address at operand address */
ARCH_DEP(vstore2) ( regs->cpuad, effective_addr2, b2, regs );
}
/*-------------------------------------------------------------------*/
/* B202 STIDP - Store CPU ID [S] */
/*-------------------------------------------------------------------*/
DEF_INST(store_cpu_id)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
U64 dreg; /* Double word workarea */
S(inst, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
DW_CHECK(effective_addr2, regs);
/* Load the CPU ID */
dreg = sysblk.cpuid;
/* If first digit of serial is zero, insert processor id */
if ((dreg & 0x00F0000000000000ULL) == 0)
dreg |= (U64)(regs->cpuad & 0x0F) << 52;
/* Store CPU ID at operand address */
ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs );
}
/*-------------------------------------------------------------------*/
/* B209 STPT - Store CPU Timer [S] */
/*-------------------------------------------------------------------*/
DEF_INST(store_cpu_timer)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
U64 dreg; /* Double word workarea */
S(inst, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
DW_CHECK(effective_addr2, regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SPT))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Obtain the TOD clock update lock */
obtain_lock (&sysblk.todlock);
/* Save the CPU timer value */
dreg = --regs->ptimer;
/* Release the TOD clock update lock */
release_lock (&sysblk.todlock);
/* Obtain the interrupt lock */
obtain_lock (&sysblk.intlock);
/* reset the cpu timer pending flag according to its value */
if( (S64)regs->ptimer < 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 the interrupt lock */
release_lock (&sysblk.intlock);
regs->psw.IA -= regs->psw.ilc;
regs->psw.IA &= ADDRESS_MAXWRAP(regs);
RETURN_INTCHECK(regs);
}
}
else
OFF_IC_PTIMER(regs);
/* Release the interrupt lock */
release_lock (&sysblk.intlock);
/* Store CPU timer value at operand location */
ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs );
// /*debug*/logmsg("Store CPU timer=%16.16llX\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, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
FW_CHECK(effective_addr2, regs);
/* Store prefix register at operand address */
ARCH_DEP(vstore4) ( regs->PX, effective_addr2, b2, regs );
}
#ifdef FEATURE_STORE_SYSTEM_INFORMATION
/*-------------------------------------------------------------------*/
/* B27D STSI - Store System Information [S] */
/*-------------------------------------------------------------------*/
DEF_INST(store_system_information)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
RADR n; /* Absolute address */
int i;
SYSIB111 *sysib111; /* Basic machine conf */
SYSIB121 *sysib121; /* Basic machine CPU */
SYSIB122 *sysib122; /* Basic machine CPUs */
#if 0
SYSIB221 *sysib221; /* LPAR CPU */
SYSIB222 *sysib222; /* LPAR CPUs */
SYSIB322 *sysib322; /* VM CPUs */
SYSIBVMDB *sysib322; /* VM description block */
#endif
static BYTE manufact[16] = { 0xD1,0xC1,0xD5,0xD1,0xC1,0xC5,0xC7,0xC5,
0xD9,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
static BYTE plant[4] = { 0xE9,0xE9,0x40,0x40 };
static BYTE hexebcdic[16] = { 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
0xF8,0xF9,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6 };
static BYTE model[8] = { 0xC8,0xC5,0xD9,0xC3,0xE4,0xD3,0xC5,0xE2 };
static BYTE mpfact[32] = { 0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B,
0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B,
0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B,
0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B };
#define STSI_CAPACITY 2
S(inst, execflag, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
/* Check function code */
if((regs->GR_L(0) & STSI_GPR0_FC_MASK) > STSI_GPR0_FC_BASIC)
{
regs->psw.cc = 3;
return;
}
/* Program check if reserved bit 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_CURRENT)
{
regs->GR_L(0) |= STSI_GPR0_FC_BASIC;
// regs->GR_L(0) |= STSI_GPR0_FC_LPAR;
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 */
if( ((regs->GR_L(0) & STSI_GPR0_FC_MASK) == 0x10000000
&& (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) == 1
&& (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) > 1)
|| (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) == 0
|| (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) == 0
|| (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) > 2
|| (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) > 2)
{
regs->psw.cc = 3;
return;
}
/* Obtain absolute address of main storage block,
check protection, and set reference and change bits */
n = LOGICAL_TO_ABS (effective_addr2, b2, regs,
ACCTYPE_WRITE, regs->psw.pkey);
switch(regs->GR_L(0) & STSI_GPR0_FC_MASK) {
case STSI_GPR0_FC_BASIC:
switch(regs->GR_L(0) & STSI_GPR0_SEL1_MASK) {
case 1:
switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) {
case 1:
sysib111 = (SYSIB111*)(sysblk.mainstor + n);
memset(sysib111, 0x00, sizeof(SYSIB111));
memcpy(sysib111->manufact,manufact,sizeof(manufact));
for(i = 0; i < 4; i++)
sysib111->type[i] =
hexebcdic[(sysblk.cpuid >> (28 - (i*4))) & 0x0F];
memset(sysib111->model, 0x40, sizeof(sysib111->model));
memcpy(sysib111->model, model, sizeof(model));
memset(sysib111->seqc,0xF0,sizeof(sysib111->seqc));
for(i = 0; i < 6; i++)
sysib111->seqc[(sizeof(sysib111->seqc) - 6) + i] =
hexebcdic[(sysblk.cpuid >> (52 - (i*4))) & 0x0F];
memcpy(sysib111->plant,plant,sizeof(plant));
regs->psw.cc = 0;
break;
default:
regs->psw.cc = 3;
} /* selector 2 */
break;
case 2:
switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) {
case 1:
sysib121 = (SYSIB121*)(sysblk.mainstor + n);
memset(sysib121, 0x00, sizeof(SYSIB121));
memset(sysib121->seqc,0xF0,sizeof(sysib121->seqc));
for(i = 0; i < 6; i++)
sysib121->seqc[(sizeof(sysib121->seqc) - 6) + i] =
hexebcdic[sysblk.cpuid >> (52 - (i*4)) & 0x0F];
memcpy(sysib121->plant,plant,sizeof(plant));
STORE_HW(sysib121->cpuad,regs->cpuad);
regs->psw.cc = 0;
break;
case 2:
sysib122 = (SYSIB122*)(sysblk.mainstor + n);
memset(sysib122, 0x00, sizeof(SYSIB122));
STORE_FW(sysib122->cap, STSI_CAPACITY);
STORE_HW(sysib122->totcpu, MAX_CPU_ENGINES);
STORE_HW(sysib122->confcpu, sysblk.numcpu);
STORE_HW(sysib122->sbcpu, MAX_CPU_ENGINES - sysblk.numcpu);
memcpy(sysib122->mpfact,mpfact,(MAX_CPU_ENGINES-1)*2);
regs->psw.cc = 0;
break;
default:
regs->psw.cc = 3;
} /* selector 2 */
break;
default:
regs->psw.cc = 3;
} /* selector 1 */
break;
default:
regs->psw.cc = 3;
} /* function code */
}
#endif /*FEATURE_STORE_SYSTEM_INFORMATION*/
/*-------------------------------------------------------------------*/
/* AC STNSM - Store Then And Systen Mask [SI] */
/*-------------------------------------------------------------------*/
DEF_INST(store_then_and_system_mask)
{
BYTE i2; /* Immediate byte of opcode */
int b1; /* Base of effective addr */
VADR effective_addr1; /* Effective address */
#if defined(OPTION_REDUCED_INVAL)
int realmode;
int space;
int armode;
#endif
SI(inst, execflag, regs, i2, b1, effective_addr1);
PRIV_CHECK(regs);
#if defined(OPTION_REDUCED_INVAL)
realmode = REAL_MODE(&regs->psw);
armode = (regs->psw.armode == 1);
space = (regs->psw.space == 1);
#endif
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_STNSM))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Store current system mask value into storage operand */
ARCH_DEP(vstoreb) ( regs->psw.sysmask, effective_addr1, b1, regs );
INVALIDATE_AIA(regs);
#if !defined(OPTION_REDUCED_INVAL)
INVALIDATE_AEA_ALL(regs);
#endif
/* AND system mask with immediate operand */
regs->psw.sysmask &= i2;
#if defined(OPTION_REDUCED_INVAL)
if ((realmode != REAL_MODE(&regs->psw)) ||
(armode != (regs->psw.armode == 1)) ||
(space != (regs->psw.space == 1)))
INVALIDATE_AEA_ALL(regs);
#endif
SET_IC_EXTERNAL_MASK(regs);
SET_IC_MCK_MASK(regs);
SET_IC_IO_MASK(regs);
SET_IC_PER_MASK(regs);
RETURN_INTCHECK(regs);
}
/*-------------------------------------------------------------------*/
/* AD STOSM - Store Then Or Systen Mask [SI] */
/*-------------------------------------------------------------------*/
DEF_INST(store_then_or_system_mask)
{
BYTE i2; /* Immediate byte of opcode */
int b1; /* Base of effective addr */
VADR effective_addr1; /* Effective address */
SI(inst, execflag, regs, i2, b1, effective_addr1);
PRIV_CHECK(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_STOSM))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Store current system mask value into storage operand */
ARCH_DEP(vstoreb) ( regs->psw.sysmask, effective_addr1, b1, regs );
/* OR system mask with immediate operand */
regs->psw.sysmask |= i2;
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
/* DAT must be off in XC mode */
if(regs->sie_state
&& (regs->siebk->mx & SIE_MX_XC)
&& (regs->psw.sysmask & PSW_DATMODE) )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
/* For ECMODE, bits 0 and 2-4 of system mask must be zero */
if (
#if defined(FEATURE_BCMODE)
regs->psw.ecmode &&
#endif /*defined(FEATURE_BCMODE)*/
(regs->psw.sysmask & 0xB8) != 0)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
SET_IC_EXTERNAL_MASK(regs);
SET_IC_MCK_MASK(regs);
SET_IC_IO_MASK(regs);
SET_IC_PER_MASK(regs);
INVALIDATE_AIA(regs);
INVALIDATE_AEA_ALL(regs);
RETURN_INTCHECK(regs);
}
/*-------------------------------------------------------------------*/
/* 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, execflag, regs, r1, r2);
PRIV_CHECK(regs);
/* R2 register contains operand real storage address */
n = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
/* Program check if operand not on fullword boundary */
FW_CHECK(n, regs);
/* Store R1 register at second operand location */
ARCH_DEP(vstore4) (regs->GR_L(r1), n, USE_REAL_ADDR, regs );
#if defined(FEATURE_PER2)
/* Storage alteration must be enabled for STURA to be recognised */
if( EN_IC_PER_SA(regs) && EN_IC_PER_STURA(regs) )
{
ON_IC_PER_SA(regs) ;
ON_IC_PER_STURA(regs) ;
regs->perc &= 0xFFFC; /* zero STD ID part of PER code */
}
#endif /*defined(FEATURE_PER2)*/
}
#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 */
int protect; /* 1=ALE or page protection */
RRE(inst, execflag, regs, r1, r2);
/* Program check if ASF control bit is zero */
if (!ASF_ENABLED(regs))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
/* Set condition code 0 if ALET value is 0 */
if (regs->AR(r1) == ALET_PRIMARY)
{
regs->psw.cc = 0;
return;
}
/* Set condition code 3 if ALET value is 1 */
if (regs->AR(r1) == ALET_SECONDARY)
{
regs->psw.cc = 3;
return;
}
/* Perform ALET translation using EAX value from register
R2 bits 0-15, and set condition code 3 if exception */
if (ARCH_DEP(translate_alet) (regs->AR(r1), regs->GR_LHH(r2),
ACCTYPE_TAR,
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
(regs->sie_state && (regs->siebk->mx & SIE_MX_XC))
? regs->hostregs :
#endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
regs,
&asteo, aste, &protect))
{
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)*/
/*-------------------------------------------------------------------*/
/* B22C TB - Test Block [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_block)
{
int r1, r2; /* Values of R fields */
RADR n; /* Real address */
RRE(inst, execflag, regs, r1, r2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
/* Load 4K block address from R2 register */
n = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
n &= PAGEFRAME_PAGEMASK;
/* Perform serialization */
PERFORM_SERIALIZATION (regs);
/* Addressing exception if block is outside main storage */
if ( n >= regs->mainsize )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Protection exception if low-address protection is set */
if (ARCH_DEP(is_low_address_protected) (n, 0, regs))
{
#ifdef FEATURE_SUPPRESSION_ON_PROTECTION
regs->TEA = (n & STORAGE_KEY_PAGEMASK);
regs->excarid = 0;
#endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/
ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION);
}
/* Convert real address to absolute address */
n = APPLY_PREFIXING (n, regs->PX);
/* Clear the 4K block to zeroes */
memset (sysblk.mainstor + n, 0x00, PAGEFRAME_PAGESIZE);
/* Set condition code 0 if storage usable, 1 if unusable */
if (STORAGE_KEY(n) & STORKEY_BADFRM)
regs->psw.cc = 1;
else
regs->psw.cc = 0;
/* Perform serialization */
PERFORM_SERIALIZATION (regs);
/* Clear general register 0 */
GR_A(0, regs) = 0;
}
/*-------------------------------------------------------------------*/
/* E501 TPROT - Test Protection [SSE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_protection)
{
int b1, b2; /* Values of base registers */
VADR effective_addr1,
effective_addr2; /* Effective addresses */
RADR raddr; /* Real address */
RADR aaddr; /* Absolute address */
BYTE skey; /* Storage key */
BYTE akey; /* Access key */
int private = 0; /* 1=Private address space */
int protect = 0; /* 1=ALE or page protection */
int stid; /* Segment table indication */
U16 xcode; /* Exception code */
SSE(inst, execflag, regs, b1, effective_addr1, b2, effective_addr2);
PRIV_CHECK(regs);
#if defined(_FEATURE_SIE)
if(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_TPROT))
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
#endif /*defined(_FEATURE_SIE)*/
/* Convert logical address to real address */
if (REAL_MODE(&regs->psw))
raddr = effective_addr1;
else {
/* Return condition code 3 if translation exception */
if (ARCH_DEP(translate_addr) (effective_addr1, b1, regs,
ACCTYPE_TPROT, &raddr,
&xcode, &private, &protect,
&stid))
{
regs->psw.cc = 3;
return;
}
}
/* Convert real address to absolute address */
aaddr = APPLY_PREFIXING (raddr, regs->PX);
/* Program check if absolute address is outside main storage */
if (aaddr >= regs->mainsize)
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
#if defined(_FEATURE_SIE)
if(regs->sie_state && !regs->sie_pref)
{
U16 sie_xcode;
int sie_private,
sie_stid;
/* Under SIE TPROT also indicates if the host is using
page protection */
#if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
if (SIE_TRANSLATE_ADDR (regs->sie_mso + aaddr,
b1,
regs->hostregs, ACCTYPE_SIE, &aaddr, &sie_xcode,
&sie_private, &protect, &sie_stid))
#else /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
if (SIE_TRANSLATE_ADDR (regs->sie_mso + aaddr,
USE_PRIMARY_SPACE,
regs->hostregs, ACCTYPE_SIE, &aaddr, &sie_xcode,
&sie_private, &protect, &sie_stid))
#endif /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
longjmp(regs->progjmp, SIE_INTERCEPT_INST);
/* Convert host real address to host absolute address */
aaddr = APPLY_PREFIXING (aaddr, regs->hostregs->PX);
if (aaddr >= regs->hostregs->mainsize)
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
}
#endif /*defined(_FEATURE_SIE)*/
/* Load access key from operand 2 address bits 24-27 */
akey = effective_addr2 & 0xF0;
/* Load the storage key for the absolute address */
skey = STORAGE_KEY(aaddr);
/* Return condition code 2 if location is fetch protected */
if (ARCH_DEP(is_fetch_protected) (effective_addr1, skey, akey,
private, 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,
private, protect, regs))
regs->psw.cc = 1;
else
/* Return condition code 0 if location is not protected */
regs->psw.cc = 0;
}
#if defined(FEATURE_TRACING)
/*-------------------------------------------------------------------*/
/* 99 TRACE - Trace [RS] */
/*-------------------------------------------------------------------*/
DEF_INST(trace)
{
int r1, r3; /* Register numbers */
int b2; /* effective address base */
VADR effective_addr2; /* effective address */
#if defined(FEATURE_TRACING)
U32 op; /* Operand */
#endif /*defined(FEATURE_TRACING)*/
RS(inst, execflag, regs, r1, r3, b2, effective_addr2);
PRIV_CHECK(regs);
FW_CHECK(effective_addr2, regs);
#if defined(FEATURE_TRACING)
/* Exit if explicit tracing (control reg 12 bit 31) is off */
if ( (regs->CR(12) & CR12_EXTRACE) == 0 )
return;
/* Fetch the trace operand */
op = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs );
/* Exit if bit zero of the trace operand is one */
if ( (op & 0x80000000) )
return;
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
regs->CR(12) = ARCH_DEP(trace_tr) (r1, r3, op, regs);
#endif /*defined(FEATURE_TRACING)*/
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
}
#endif /*defined(FEATURE_TRACING)*/
#if !defined(_GEN_ARCH)
#if defined(_ARCHMODE2)
#define _GEN_ARCH _ARCHMODE2
#include "control.c"
#endif
#if defined(_ARCHMODE3)
#undef _GEN_ARCH
#define _GEN_ARCH _ARCHMODE3
#include "control.c"
#endif
#endif /*!defined(_GEN_ARCH)*/