/*-------------------------------------------------------------------*/ static int ARCH_DEP(display_real) (REGS *regs, RADR raddr, char *buf, int draflag) { RADR aaddr; /* Absolute storage address */ int i, j; /* Loop counters */ int n = 0; /* Number of bytes in buffer */ char hbuf[40]; /* Hexadecimal buffer */ BYTE cbuf[17]; /* Character buffer */ BYTE c; /* Character work area */ #if defined(FEATURE_INTERVAL_TIMER) if(ITIMER_ACCESS(raddr,16)) ARCH_DEP(store_int_timer)(regs); #endif if (draflag) { n = sprintf (buf, "R:"F_RADR":", raddr); } aaddr = APPLY_PREFIXING (raddr, regs->PX); if (aaddr > regs->mainlim) { n += sprintf (buf+n, " Real address is not valid"); return n; } n += sprintf (buf+n, "K:%2.2X=", STORAGE_KEY(aaddr, regs)); memset (hbuf, SPACE, sizeof(hbuf)); memset (cbuf, SPACE, sizeof(cbuf)); for (i = 0, j = 0; i < 16; i++) { c = regs->mainstor[aaddr++]; j += sprintf (hbuf+j, "%2.2X", c); if ((aaddr & 0x3) == 0x0) hbuf[j++] = SPACE; c = guest_to_host(c); if (!isprint(c)) c = '.'; cbuf[i] = c; if ((aaddr & PAGEFRAME_BYTEMASK) == 0x000) break; } /* end for(i) */ n += sprintf (buf+n, "%36.36s %16.16s", hbuf, cbuf); return n; } /* end function display_real */
/*-------------------------------------------------------------------*/ int ARCH_DEP(load_main) (char *fname, RADR startloc) { int fd; int len; int rc = 0; RADR pageaddr; U32 pagesize; fd = HOPEN (fname, O_RDONLY|O_BINARY); if (fd < 0) { if(errno != ENOENT) WRMSG(HHC00600,"E",fname,"open()",strerror(errno)); return fd; } pagesize = PAGEFRAME_PAGESIZE - (startloc & PAGEFRAME_BYTEMASK); pageaddr = startloc; for( ; ; ) { if (pageaddr >= sysblk.mainsize) { WRMSG(HHC00603, "W", fname); close(fd); return rc; } len = read(fd, sysblk.mainstor + pageaddr, pagesize); if (len > 0) { STORAGE_KEY(pageaddr, &sysblk) |= STORKEY_REF|STORKEY_CHANGE; rc += len; } if (len < (int)pagesize) { close(fd); return rc; } pageaddr += PAGEFRAME_PAGESIZE; pageaddr &= PAGEFRAME_PAGEMASK; pagesize = PAGEFRAME_PAGESIZE; } } /* end function load_main */
/*-------------------------------------------------------------------*/ static void ARCH_DEP(alter_display_real) (char *opnd, REGS *regs) { U64 saddr, eaddr; /* Range start/end addresses */ U64 maxadr; /* Highest real storage addr */ RADR raddr; /* Real storage address */ RADR aaddr; /* Absolute storage address */ int len; /* Number of bytes to alter */ int i; /* Loop counter */ BYTE newval[32]; /* Storage alteration value */ char buf[100]; /* Message buffer */ /* Set limit for address range */ #if defined(FEATURE_ESAME) maxadr = 0xFFFFFFFFFFFFFFFFULL; #else /*!defined(FEATURE_ESAME)*/ maxadr = 0x7FFFFFFF; #endif /*!defined(FEATURE_ESAME)*/ /* Parse the range or alteration operand */ len = parse_range (opnd, maxadr, &saddr, &eaddr, newval); if (len < 0) return; raddr = saddr; /* Alter real storage */ if (len > 0) { for (i = 0; i < len && raddr+i <= regs->mainlim; i++) { aaddr = raddr + i; aaddr = APPLY_PREFIXING (aaddr, regs->PX); regs->mainstor[aaddr] = newval[i]; STORAGE_KEY(aaddr, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* end for(i) */ } /* Display real storage */ for (i = 0; i < 999 && raddr <= eaddr; i++) { ARCH_DEP(display_real) (regs, raddr, buf, 1); logmsg ("%s\n", buf); raddr += 16; } /* end for(i) */ } /* end function alter_display_real */
/*-------------------------------------------------------------------*/ void ARCH_DEP(diag224_call) (int r1, int r2, REGS *regs) { RADR abs; /* abs addr of data area */ BYTE *p; /* pointer to the data area */ unsigned int i; /* loop index */ //FIXME : this is probably incomplete. // see linux/arch/s390/hypfs/hypfs_diag.c UNREFERENCED(r1); abs = APPLY_PREFIXING (regs->GR_L(r2), regs->PX); /* Program check if data area is not on a page boundary */ if ( (abs & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if data area is outside main storage */ if ( abs > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Point to DIAG 224 data area */ p = regs->mainstor + abs; /* Mark page referenced */ STORAGE_KEY(abs, regs) |= STORKEY_REF | STORKEY_CHANGE; /* First byte contains the number of entries - 1 */ *p = 5; /* Clear the next 15 bytes */ memset (p + 1, 0, 15); /* Set the 6 possible entries */ p += 16; memcpy(p,diag224_cputable,sizeof(diag224_cputable)-1); /* Convert to EBCDIC */ for (i = 0; i < sizeof(diag224_cputable); i++) p[i] = host_to_guest(p[i]); } /* end function diag224_call */
/*-------------------------------------------------------------------*/ static S64 ARCH_DEP(read_file)(char *fname, CREG sto, S64 seek, S64 size) { int fd, nread; U64 totread = 0; fd = HOPEN (fname, O_RDONLY|O_BINARY); if (fd < 0) { if(errno != ENOENT) WRMSG (HHC00600, "E", fname, "open()", strerror(errno)); return -1; } if(lseek(fd, (off_t)seek, SEEK_SET) == (off_t)seek) { #if defined(FEATURE_ESAME) sto &= ASCE_TO; #else /*!defined(FEATURE_ESAME)*/ sto &= STD_STO; #endif /*!defined(FEATURE_ESAME)*/ for( ; size > 0 ; sto += sizeof(sto)) { #if defined(FEATURE_ESAME) DBLWRD *ste; #else /*!defined(FEATURE_ESAME)*/ FWORD *ste; #endif /*!defined(FEATURE_ESAME)*/ CREG pto, pti; /* Fetch segment table entry and calc Page Table Origin */ if( sto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) ste = (DBLWRD*)(sysblk.mainstor + sto); #else /*!defined(FEATURE_ESAME)*/ ste = (FWORD*)(sysblk.mainstor + sto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pto, ste); STORAGE_KEY(sto, &sysblk) |= (STORKEY_REF); if( pto & SEGTAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pto &= ZSEGTAB_PTO; #else /*!defined(FEATURE_ESAME)*/ pto &= SEGTAB_PTO; #endif /*!defined(FEATURE_ESAME)*/ for(pti = 0; pti < 256 && size > 0; pti++, pto += sizeof(pto)) { #if defined(FEATURE_ESAME) DBLWRD *pte; #else /*!defined(FEATURE_ESAME)*/ FWORD *pte; #endif /*!defined(FEATURE_ESAME)*/ CREG pgo; BYTE *page; /* Fetch Page Table Entry to get page origin */ if( pto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) pte = (DBLWRD*)(sysblk.mainstor + pto); #else /*!defined(FEATURE_ESAME)*/ pte = (FWORD*)(sysblk.mainstor + pto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pgo, pte); STORAGE_KEY(pto, &sysblk) |= (STORKEY_REF); if( pgo & PAGETAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pgo &= ZPGETAB_PFRA; #else /*!defined(FEATURE_ESAME)*/ pgo &= PAGETAB_PFRA; #endif /*!defined(FEATURE_ESAME)*/ /* Read page into main storage */ if( pgo >= sysblk.mainsize) goto eof; page = sysblk.mainstor + pgo; nread = read(fd, page, STORAGE_KEY_PAGESIZE); totread += nread; size -= nread; if( nread != STORAGE_KEY_PAGESIZE ) goto eof; STORAGE_KEY(pgo, &sysblk) |= (STORKEY_REF|STORKEY_CHANGE); } } } eof: close(fd); return totread; }
/*-------------------------------------------------------------------*/ static S64 ARCH_DEP(write_file)(char *fname, int mode, CREG sto, S64 size) { int fd, nwrite; U64 totwrite = 0; fd = HOPEN (fname, mode |O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (fd < 0) { WRMSG (HHC00600, "E", fname, "open()", strerror(errno)); return -1; } #if defined(FEATURE_ESAME) sto &= ASCE_TO; #else /*!defined(FEATURE_ESAME)*/ sto &= STD_STO; #endif /*!defined(FEATURE_ESAME)*/ for( ; size > 0 ; sto += sizeof(sto)) { #if defined(FEATURE_ESAME) DBLWRD *ste; #else /*!defined(FEATURE_ESAME)*/ FWORD *ste; #endif /*!defined(FEATURE_ESAME)*/ CREG pto, pti; /* Fetch segment table entry and calc Page Table Origin */ if( sto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) ste = (DBLWRD*)(sysblk.mainstor + sto); #else /*!defined(FEATURE_ESAME)*/ ste = (FWORD*)(sysblk.mainstor + sto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pto, ste); STORAGE_KEY(sto, &sysblk) |= (STORKEY_REF); if( pto & SEGTAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pto &= ZSEGTAB_PTO; #else /*!defined(FEATURE_ESAME)*/ pto &= SEGTAB_PTO; #endif /*!defined(FEATURE_ESAME)*/ for(pti = 0; pti < 256 && size > 0; pti++, pto += sizeof(pto)) { #if defined(FEATURE_ESAME) DBLWRD *pte; #else /*!defined(FEATURE_ESAME)*/ FWORD *pte; #endif /*!defined(FEATURE_ESAME)*/ CREG pgo; BYTE *page; /* Fetch Page Table Entry to get page origin */ if( pto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) pte = (DBLWRD*)(sysblk.mainstor + pto); #else /*!defined(FEATURE_ESAME)*/ pte = (FWORD*)(sysblk.mainstor + pto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pgo, pte); STORAGE_KEY(pto, &sysblk) |= (STORKEY_REF); if( !(pgo & PAGETAB_INVALID) ) { #if defined(FEATURE_ESAME) pgo &= ZPGETAB_PFRA; #else /*!defined(FEATURE_ESAME)*/ pgo &= PAGETAB_PFRA; #endif /*!defined(FEATURE_ESAME)*/ /* Write page to SCE disk */ if( pgo >= sysblk.mainsize) goto eof; page = sysblk.mainstor + pgo; nwrite = write(fd, page, STORAGE_KEY_PAGESIZE); totwrite += nwrite; if( nwrite != STORAGE_KEY_PAGESIZE ) goto eof; STORAGE_KEY(pgo, &sysblk) |= (STORKEY_REF); } size -= STORAGE_KEY_PAGESIZE; } } eof: close(fd); return totwrite; }
/*-------------------------------------------------------------------*/ int ARCH_DEP(load_main) (char *fname, RADR startloc, int noisy) { U64 loaded; RADR aaddr; RADR pageaddr; int fd; size_t chunk; int bytes; time_t begtime, curtime; char fmt_mem[8]; fd = HOPEN (fname, O_RDONLY|O_BINARY); if (fd < 0) { if(errno != ENOENT) WRMSG(HHC00600,"E",fname,"open()",strerror(errno)); return fd; } /* Calculate size of first chunk to reach page boundary */ chunk = PAGEFRAME_PAGESIZE - (startloc & PAGEFRAME_BYTEMASK); aaddr = startloc; if (noisy) { loaded = 0; time( &begtime ); } /* Read file into storage until end of file or end of storage */ for( ; ; ) { bytes = read(fd, sysblk.mainstor + aaddr, chunk); /* Check for I/O error */ if (bytes < 0) { // "SCE file %s: error in function %s: %s" WRMSG(HHC00600, "E", fname, "read()",strerror(errno)); close(fd); return -1; } /* Check for end-of-file */ if (bytes == 0) { close(fd); return 0; } /* Update the storage keys for all of the pages we just read */ chunk = bytes; pageaddr = aaddr; for ( ; chunk > 0; chunk -= PAGEFRAME_PAGESIZE) { STORAGE_KEY(pageaddr, &sysblk) |= STORKEY_REF|STORKEY_CHANGE; pageaddr += PAGEFRAME_PAGESIZE; } aaddr += bytes; aaddr &= PAGEFRAME_PAGEMASK; /* Check if end of storge reached */ if (aaddr >= sysblk.mainsize) { int rc; if (read(fd, &rc, 1) > 0) { rc = +1; if (noisy) { // "SCE file %s: load main terminated at end of mainstor" WRMSG(HHC00603, "W", fname); } } else /* ignore any error; we're at end of storage anyway */ rc = 0; close(fd); return rc; } /* Issue periodic progress messages */ if (noisy) { loaded += bytes; time( &curtime ); if (difftime( curtime, begtime ) > 2.0) { begtime = curtime; // "%s bytes %s so far..." WRMSG( HHC02317, "I", fmt_memsize_rounded( loaded, fmt_mem, sizeof( fmt_mem )), "loaded" ); } } chunk = (64 * 1024 * 1024); if (chunk > (sysblk.mainsize - aaddr)) chunk = (sysblk.mainsize - aaddr); } /* end for( ; ; ) */ } /* end function load_main */
/*-------------------------------------------------------------------*/ static void ARCH_DEP(external_interrupt) (int code, REGS *regs) { RADR pfx; PSA *psa; int rc; PTT(PTT_CL_SIG,"*EXTINT",code,regs->cpuad,regs->psw.IA_L); #if defined(_FEATURE_SIE) /* Set the main storage reference and change bits */ if(SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) && !SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) && !SIE_FEATB(regs, EC0, EXTA) #endif ) { /* Point to SIE copy of PSA in state descriptor */ psa = (void*)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_IP_PSA_OFFSET); STORAGE_KEY(SIE_STATE(regs), regs->hostregs) |= (STORKEY_REF | STORKEY_CHANGE); } else #endif /*defined(_FEATURE_SIE)*/ { /* Point to PSA in main storage */ pfx = regs->PX; #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) SIE_TRANSLATE(&pfx, ACCTYPE_SIE, regs); #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ psa = (void*)(regs->mainstor + pfx); STORAGE_KEY(pfx, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* Store the interrupt code in the PSW */ regs->psw.intcode = code; /* Zero extcpuad field unless extcall or ems signal or blockio */ if(code != EXT_EXTERNAL_CALL_INTERRUPT #if defined(FEATURE_VM_BLOCKIO) && code != EXT_BLOCKIO_INTERRUPT #endif /* defined(FEATURE_VM_BLOCKIO) */ && code != EXT_EMERGENCY_SIGNAL_INTERRUPT) STORE_HW(psa->extcpad,0); #if defined(FEATURE_BCMODE) /* For ECMODE, store external interrupt code at PSA+X'86' */ if ( ECMODE(®s->psw) ) #endif /*defined(FEATURE_BCMODE)*/ STORE_HW(psa->extint,code); if ( !SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) || SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) || SIE_FEATB(regs, EC0, EXTA) #endif ) { /* Store current PSW at PSA+X'18' */ ARCH_DEP(store_psw) (regs, psa->extold); /* Load new PSW from PSA+X'58' */ rc = ARCH_DEP(load_psw) (regs, psa->extnew); if ( rc ) { RELEASE_INTLOCK(regs); ARCH_DEP(program_interrupt)(regs, rc); } } #if defined(FEATURE_INTERVAL_TIMER) /* Ensure the interval timer is uptodate */ ARCH_DEP(store_int_timer_nolock) (regs); #endif RELEASE_INTLOCK(regs); if ( SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) && !SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) && !SIE_FEATB(regs, EC0, EXTA) #endif ) longjmp (regs->progjmp, SIE_INTERCEPT_EXT); else longjmp (regs->progjmp, SIE_NO_INTERCEPT); } /* end function external_interrupt */
/*-------------------------------------------------------------------*/ void ARCH_DEP(diagnose_call) (VADR effective_addr2, int b2, int r1, int r2, REGS *regs) { #ifdef FEATURE_HERCULES_DIAGCALLS U32 n; /* 32-bit operand value */ #endif /*FEATURE_HERCULES_DIAGCALLS*/ U32 code; code = effective_addr2; switch(code) { #if defined(FEATURE_IO_ASSIST) case 0x002: /*---------------------------------------------------------------*/ /* Diagnose 002: Update Interrupt Interlock Control Bit in PMCW */ /*---------------------------------------------------------------*/ ARCH_DEP(diagnose_002) (regs, r1, r2); break; #endif case 0x01F: /*---------------------------------------------------------------*/ /* Diagnose 01F: Power Off */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* The poweroff diagnose is only valid on the 9221 */ if (sysblk.cpumodel != 0x9221 /* and r1/r2 must contain C'POWEROFF' in EBCDIC */ || regs->GR_L(r1) != 0xD7D6E6C5 || regs->GR_L(r2) != 0xD9D6C6C6) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); /* Release the configuration */ do_shutdown(); /* Power Off: exit hercules */ exit(0); #if defined(FEATURE_HYPERVISOR) || defined(FEATURE_EMULATE_VM) case 0x044: /*---------------------------------------------------------------*/ /* Diagnose 044: Voluntary Time Slice End */ /*---------------------------------------------------------------*/ ARCH_DEP(scpend_call) (); break; #endif #ifdef FEATURE_MSSF_CALL case 0x080: /*---------------------------------------------------------------*/ /* Diagnose 080: MSSF Call */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(mssf_call) (r1, r2, regs); break; #endif /*FEATURE_MSSF_CALL*/ #if defined(FEATURE_HYPERVISOR) || defined(FEATURE_EMULATE_VM) case 0x09C: /*---------------------------------------------------------------*/ /* Diagnose 09C: Voluntary Time Slice End With Target CPU */ /*---------------------------------------------------------------*/ ARCH_DEP(scpend_call) (); // (treat same as DIAG X'44') break; #endif #if defined(FEATURE_HYPERVISOR) case 0x204: /*---------------------------------------------------------------*/ /* Diagnose 204: LPAR RMF Interface */ /*---------------------------------------------------------------*/ ARCH_DEP(diag204_call) (r1, r2, regs); regs->psw.cc = 0; break; case 0x224: /*---------------------------------------------------------------*/ /* Diagnose 224: CPU Names */ /*---------------------------------------------------------------*/ ARCH_DEP(diag224_call) (r1, r2, regs); regs->psw.cc = 0; break; #endif /*defined(FEATURE_HYPERVISOR)*/ #if 0 case 0x21C: /*---------------------------------------------------------------*/ /* Diagnose 21C: ???? */ /*---------------------------------------------------------------*/ /*INCOMPLETE*/ regs->psw.cc = 0; break; #endif #if 0 case 0x288;: /*---------------------------------------------------------------*/ /* Diagnose 288: Control Virtual Machine Time Bomb */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(vm_timebomb) (r1, r2, regs); break; #endif #ifdef FEATURE_EMULATE_VM case 0x000: /*---------------------------------------------------------------*/ /* Diagnose 000: Store Extended Identification Code */ /*---------------------------------------------------------------*/ ARCH_DEP(extid_call) (r1, r2, regs); break; case 0x008: /*---------------------------------------------------------------*/ /* Diagnose 008: Virtual Console Function */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Process CP command and set condition code */ regs->psw.cc = ARCH_DEP(cpcmd_call) (r1, r2, regs); break; case 0x00C: /*---------------------------------------------------------------*/ /* Diagnose 00C: Pseudo Timer */ /*---------------------------------------------------------------*/ ARCH_DEP(pseudo_timer) (code, r1, r2, regs); break; case 0x024: /*---------------------------------------------------------------*/ /* Diagnose 024: Device Type and Features */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(diag_devtype) (r1, r2, regs); break; case 0x05C: /*---------------------------------------------------------------*/ /* Diagnose 05C: Error Message Editing */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ regs->psw.cc = 0; break; case 0x060: /*---------------------------------------------------------------*/ /* Diagnose 060: Virtual Machine Storage Size */ /*---------------------------------------------------------------*/ /* Load main storage size in bytes into R1 register */ regs->GR_L(r1) = regs->mainlim + 1; break; case 0x064: /*---------------------------------------------------------------*/ /* Diagnose 064: Named Saved Segment Manipulation */ /*---------------------------------------------------------------*/ /* Return code 44 cond code 2 means segment does not exist */ regs->GR_L(r2) = 44; regs->psw.cc = 2; break; case 0x0A4: /*---------------------------------------------------------------*/ /* Diagnose 0A4: Synchronous I/O (Standard CMS Blocksize) */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(syncblk_io) (r1, r2, regs); // logmsg ("Diagnose X\'0A4\': CC=%d, R15=%8.8X\n", /*debug*/ // regs->psw.cc, regs->GR_L(15)); /*debug*/ break; case 0x0A8: /*---------------------------------------------------------------*/ /* Diagnose 0A8: Synchronous General I/O */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(syncgen_io) (r1, r2, regs); // logmsg ("Diagnose X\'0A8\': CC=%d, R15=%8.8X\n", /*debug*/ // regs->psw.cc, regs->GR_L(15)); /*debug*/ break; case 0x0B0: /*---------------------------------------------------------------*/ /* Diagnose 0B0: Access Re-IPL Data */ /*---------------------------------------------------------------*/ ARCH_DEP(access_reipl_data) (r1, r2, regs); break; case 0x0DC: /*---------------------------------------------------------------*/ /* Diagnose 0DC: Control Application Monitor Record Collection */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ regs->GR_L(r2) = 0; regs->psw.cc = 0; break; case 0x210: /*---------------------------------------------------------------*/ /* Diagnose 210: Retrieve Device Information */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(device_info) (r1, r2, regs); break; case 0x214: /*---------------------------------------------------------------*/ /* Diagnose 214: Pending Page Release */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(diag_ppagerel) (r1, r2, regs); break; case 0x220: /*---------------------------------------------------------------*/ /* Diagnose 220: TOD Epoch */ /*---------------------------------------------------------------*/ ODD_CHECK(r2, regs); switch(regs->GR_L(r1)) { case 0: /* Obtain TOD features */ regs->GR_L(r2) =0xc0000000; regs->GR_L(r2+1)=0x00000000; break; case 1: /* Obtain TOD offset to real TOD in R2, R2+1 */ regs->GR_L(r2) = (regs->tod_epoch >> 24) & 0xFFFFFFFF; regs->GR_L(r2+1)= (regs->tod_epoch << 8) & 0xFFFFFFFF; break; default: ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); } break; case 0x23C: /*---------------------------------------------------------------*/ /* Diagnose 23C: Address Space Services */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ regs->GR_L(r2) = 0; break; #if defined(FEATURE_VM_BLOCKIO) case 0x250: /*---------------------------------------------------------------*/ /* Diagnose 250: Standardized Block I/O */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(vm_blockio) (r1, r2, regs); break; #endif /*defined(FEATURE_VM_BLOCKIO)*/ case 0x260: /*---------------------------------------------------------------*/ /* Diagnose 260: Access Certain Virtual Machine Information */ /*---------------------------------------------------------------*/ ARCH_DEP(vm_info) (r1, r2, regs); break; case 0x264: /*---------------------------------------------------------------*/ /* Diagnose 264: CP Communication */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ PTT_ERR("*DIAG264",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 0; break; case 0x270: /*---------------------------------------------------------------*/ /* Diagnose 270: Pseudo Timer Extended */ /*---------------------------------------------------------------*/ ARCH_DEP(pseudo_timer) (code, r1, r2, regs); break; case 0x274: /*---------------------------------------------------------------*/ /* Diagnose 274: Set Timezone Interrupt Flag */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ PTT_ERR("*DIAG274",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 0; break; #endif /*FEATURE_EMULATE_VM*/ #ifdef FEATURE_PROGRAM_DIRECTED_REIPL case 0x308: /*---------------------------------------------------------------*/ /* Diagnose 308: IPL functions */ /*---------------------------------------------------------------*/ switch(r2) { TID tid; /* Thread identifier */ char *ipltype; /* "ipl" or "iplc" */ int rc; case DIAG308_IPL_CLEAR: ipltype = "iplc"; goto diag308_cthread; case DIAG308_IPL_NORMAL: ipltype = "ipl"; diag308_cthread: rc = create_thread(&tid, DETACHED, stop_cpus_and_ipl, ipltype, "Stop cpus and ipl"); if(rc) WRMSG(HHC00102, "E", strerror(rc)); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); break; case DIAG308_SET_PARAM: /* INCOMPLETE */ regs->GR(1) = DIAG308_RC_OK; break; case DIAG308_STORE_PARAM: /* INCOMPLETE */ regs->GR(1) = DIAG308_RC_OK; break; default: ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); } /* end switch(r2) */ break; #endif /*FEATURE_PROGRAM_DIRECTED_REIPL*/ #ifdef FEATURE_HERCULES_DIAGCALLS case 0xF00: /*---------------------------------------------------------------*/ /* Diagnose F00: Hercules normal mode */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); sysblk.inststep = 0; SET_IC_TRACE; break; case 0xF04: /*---------------------------------------------------------------*/ /* Diagnose F04: Hercules single step mode */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); sysblk.inststep = 1; SET_IC_TRACE; break; case 0xF08: /*---------------------------------------------------------------*/ /* Diagnose F08: Hercules get instruction counter */ /*---------------------------------------------------------------*/ regs->GR_L(r1) = (U32)INSTCOUNT(regs); break; case 0xF0C: /*---------------------------------------------------------------*/ /* Diagnose F0C: Set/reset bad frame indicator */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Load 4K block address from R2 register */ n = regs->GR_L(r2) & ADDRESS_MAXWRAP(regs); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) { ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); break; } /* Update the storage key from R1 register bit 31 */ STORAGE_KEY(n, regs) &= ~(STORKEY_BADFRM); STORAGE_KEY(n, regs) |= regs->GR_L(r1) & STORKEY_BADFRM; break; case 0xF10: /*---------------------------------------------------------------*/ /* Diagnose F10: Hercules CPU stop */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); break; #if defined(OPTION_DYNAMIC_LOAD) case 0xF14: /*---------------------------------------------------------------*/ /* Diagnose F14: Hercules DLL interface */ /*---------------------------------------------------------------*/ ARCH_DEP(diagf14_call) (r1, r2, regs); break; #endif /*defined(OPTION_DYNAMIC_LOAD)*/ #if defined(_FEATURE_HOST_RESOURCE_ACCESS_FACILITY) case 0xF18: /*---------------------------------------------------------------*/ /* Diagnose F18: Hercules Access Host Resource */ /*---------------------------------------------------------------*/ ARCH_DEP(diagf18_call) (r1, r2, regs); break; #endif /* defined(_FEATURE_HOST_RESOURCE_ACCESS_FACILITY) */ #if !defined(NO_SIGABEND_HANDLER) /* The following diagnose calls cause a exigent (non-repressible) machine check, and are used for test purposes only *JJ */ case 0xFE8: /*---------------------------------------------------------------*/ /* Diagnose FE8: Simulate Illegal Instruction */ /*---------------------------------------------------------------*/ raise(SIGILL); break; case 0xFEC: /*---------------------------------------------------------------*/ /* Diagnose FEC: Simulate Floating Point Exception */ /*---------------------------------------------------------------*/ raise(SIGFPE); break; case 0xFF0: /*---------------------------------------------------------------*/ /* Diagnose FF0: Simulate Segment Violation */ /*---------------------------------------------------------------*/ CRASH(); break; case 0xFF4: /*---------------------------------------------------------------*/ /* Diagnose FF4: Simulate BUS Error */ /*---------------------------------------------------------------*/ raise(SIGBUS); break; case 0xFF8: /*---------------------------------------------------------------*/ /* Diagnose FF8: Simulate Loop */ /*---------------------------------------------------------------*/ while(1); /* (never reached) */ case 0xFFC: /*---------------------------------------------------------------*/ /* Diagnose FFC: Simulate Wait */ /*---------------------------------------------------------------*/ SLEEP(300); break; #endif /*!defined(NO_SIGABEND_HANDLER)*/ #endif /*FEATURE_HERCULES_DIAGCALLS*/ default: /*---------------------------------------------------------------*/ /* Diagnose xxx: Invalid function code */ /*---------------------------------------------------------------*/ if( HDC4(debug_diagnose, code, r1, r2, regs) ) return; /* Power Off diagnose on 4361, 9371, 9373, 9375, 9377, 9221: */ /* */ /* DS 0H */ /* DC X'8302',S(SHUTDATA) MUST BE R0 AND R2 */ /* ... */ /* DS 0H */ /* SHUTDATA DC X'0000FFFF' MUST BE X'0000FFFF' */ if (0 == r1 && 2 == r2 && sysblk.cpuversion != 0xFF && (sysblk.cpumodel == 0x4361 || (sysblk.cpumodel & 0xFFF9) == 0x9371 /* (937X) */ || sysblk.cpumodel == 0x9221) ) { if (0x0000FFFF == ARCH_DEP(vfetch4)(effective_addr2, b2, regs)) { /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); /* Release the configuration */ do_shutdown(); /* Power Off: exit hercules */ exit(0); } } #if defined(FEATURE_S370_CHANNEL) && defined(OPTION_NOP_MODEL158_DIAGNOSE) if (regs->cpumodel != 0x0158) #endif ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); return; } /* end switch(code) */ return; } /* end function diagnose_call */
/*-------------------------------------------------------------------*/ int ARCH_DEP(mssf_call) (int r1, int r2, REGS *regs) { U32 spccb_absolute_addr; /* Absolute addr of SPCCB */ U32 mssf_command; /* MSSF command word */ U32 spccblen; /* Length of SPCCB */ SPCCB_HEADER *spccb; /* -> SPCCB header */ SPCCB_CONFIG_INFO *spccbconfig; /* -> SPCCB CONFIG info */ SPCCB_CPU_INFO *spccbcpu; /* -> SPCCB CPU information */ SPCCB_CHP_STATUS *spccbchp; /* -> SPCCB channel path info */ U16 offset; /* Offset from start of SPCCB */ int i; /* loop counter */ DEVBLK *dev; /* Device block pointer */ /* R1 contains the real address of the SPCCB */ spccb_absolute_addr = APPLY_PREFIXING (regs->GR_L(r1), regs->PX); /* R2 contains the service-processor-command word */ mssf_command = regs->GR_L(r2); /* Program check if SPCCB is not on a doubleword boundary */ if ( spccb_absolute_addr & 0x00000007 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if SPCCB is outside main storage */ if ( spccb_absolute_addr > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); // /*debug*/logmsg("MSSF call %8.8X SPCCB=%8.8X\n", // /*debug*/ mssf_command, spccb_absolute_addr); /* Point to Service Processor Command Control Block */ spccb = (SPCCB_HEADER*)(regs->mainstor + spccb_absolute_addr); /* Load SPCCB length from header */ FETCH_HW(spccblen,spccb->length); /* Mark page referenced */ STORAGE_KEY(spccb_absolute_addr, regs) |= STORKEY_REF; /* Program check if end of SPCCB falls outside main storage */ if ( sysblk.mainsize - spccblen < spccb_absolute_addr ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); /* If a service signal is pending then we cannot process the request */ if( IS_IC_SERVSIG && (sysblk.servparm & SERVSIG_ADDR)) { RELEASE_INTLOCK(regs); return 2; /* Service Processor Busy */ } if( spccb_absolute_addr & 0x7ffff800 ) { spccb->resp[0] = SPCCB_REAS_NOT2KALIGN; spccb->resp[1] = SPCCB_RESP_NOT2KALIGN; } else /* Test MSSF command word */ switch (mssf_command) { case MSSF_READ_CONFIG_INFO: /* Set response code X'01F0' if SPCCB length is insufficient to contain CONFIG info */ if ( spccblen < 64 ) { spccb->resp[0] = SPCCB_REAS_BADLENGTH; spccb->resp[1] = SPCCB_RESP_BADLENGTH; break; } /* Point to SPCCB data area following SPCCB header */ spccbconfig = (SPCCB_CONFIG_INFO*)(spccb+1); memset (spccbconfig, 0, sizeof(SPCCB_CONFIG_INFO)); /* Set main storage size in SPCCB */ spccbconfig->totstori = sysblk.mainsize >> 20; spccbconfig->storisiz = 1; spccbconfig->hex04 = 0x04; spccbconfig->hex01 = 0x01; /* Set CPU array count and offset in SPCCB */ STORE_HW(spccbconfig->toticpu,sysblk.maxcpu); offset = sizeof(SPCCB_HEADER) + sizeof(SPCCB_CONFIG_INFO); STORE_HW(spccbconfig->officpu,offset); /* Set HSA array count and offset in SPCCB */ STORE_HW(spccbconfig->tothsa,0); offset += (U16)(sizeof(SPCCB_CPU_INFO) * sysblk.maxcpu); STORE_HW(spccbconfig->offhsa,offset); /* Move IPL load parameter to SPCCB */ get_loadparm (spccbconfig->loadparm); /* Build the CPU information array after the SCP info */ spccbcpu = (SPCCB_CPU_INFO*)(spccbconfig+1); for (i = 0; i < sysblk.maxcpu; i++, spccbcpu++) { memset( spccbcpu, 0, sizeof(SPCCB_CPU_INFO) ); spccbcpu->cpuaddr = i; spccbcpu->todid = 0; } /* Set response code X'0010' in SPCCB header */ spccb->resp[0] = SPCCB_REAS_COMPLETE; spccb->resp[1] = SPCCB_RESP_COMPLETE; break; case MSSF_READ_CHP_STATUS: /* Set response code X'0300' if SPCCB length is insufficient to contain channel path info */ if ( spccblen < sizeof(SPCCB_HEADER) + sizeof(SPCCB_CHP_STATUS)) { spccb->resp[0] = SPCCB_REAS_BADLENGTH; spccb->resp[1] = SPCCB_RESP_BADLENGTH; break; } /* Point to SPCCB data area following SPCCB header */ spccbchp = (SPCCB_CHP_STATUS*)(spccb+1); memset( spccbchp, 0, sizeof(SPCCB_CHP_STATUS) ); /* Identify CHPIDs used */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { for (i = 0; i < 8; i++) { if( ((0x80 >> i) & dev->pmcw.pim) ) { BYTE chpid; chpid = dev->pmcw.chpid[i]; spccbchp->installed[chpid / 8] |= 0x80 >> (chpid % 8); spccbchp->assigned[chpid / 8] |= 0x80 >> (chpid % 8); spccbchp->configured[chpid / 8] |= 0x80 >> (chpid % 8); } } } /* Set response code X'0010' in SPCCB header */ spccb->resp[0] = SPCCB_REAS_COMPLETE; spccb->resp[1] = SPCCB_RESP_COMPLETE; break; default: PTT(PTT_CL_ERR,"*DIAG080",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); /* Set response code X'06F0' for invalid MSSF command */ spccb->resp[0] = SPCCB_REAS_UNASSIGNED; spccb->resp[1] = SPCCB_RESP_UNASSIGNED; break; } /* end switch(mssf_command) */ /* Mark page changed */ STORAGE_KEY(spccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set service signal external interrupt pending */ sysblk.servparm &= ~SERVSIG_ADDR; sysblk.servparm |= spccb_absolute_addr; ON_IC_SERVSIG; /* Release the interrupt lock */ RELEASE_INTLOCK(regs); /* Return condition code 0: Command initiated */ return 0; } /* end function mssf_call */
/*-------------------------------------------------------------------*/ void ARCH_DEP(diag204_call) (int r1, int r2, REGS *regs) { DIAG204_HDR *hdrinfo; /* Header */ DIAG204_PART *partinfo; /* Partition info */ DIAG204_PART_CPU *cpuinfo; /* CPU info */ #if defined(FEATURE_EXTENDED_DIAG204) DIAG204_X_HDR *hdrxinfo; /* Header */ DIAG204_X_PART *partxinfo; /* Partition info */ DIAG204_X_PART_CPU *cpuxinfo; /* CPU info */ #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ RADR abs; /* abs addr of data area */ int i; /* loop counter */ struct rusage usage; /* RMF type data */ ETOD ETOD; /* Extended TOD clock */ U64 uCPU[MAX_CPU_ENGINES]; /* User CPU time (us) */ U64 tCPU[MAX_CPU_ENGINES]; /* Total CPU time (us) */ #if defined(FEATURE_PHYSICAL_DIAG204) static BYTE physical[8] = {0xD7,0xC8,0xE8,0xE2,0xC9,0xC3,0xC1,0xD3}; /* PHYSICAL */ #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ #if defined(FEATURE_EXTENDED_DIAG204) U64 oCPU[MAX_CPU_ENGINES]; /* Online CPU time (us) */ U64 wCPU[MAX_CPU_ENGINES]; /* Wait CPU time (us) */ #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ /* Test DIAG204 command word */ switch (regs->GR_L(r2)) { case 0x04: abs = APPLY_PREFIXING (GR_A(r1,regs), regs->PX); /* Program check if RMF data is not on a page boundary */ if ( (abs & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if RMF data area is outside main storage */ if ( abs > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Point to DIAG 204 data area */ hdrinfo = (DIAG204_HDR*)(regs->mainstor + abs); /* Mark page referenced */ STORAGE_KEY(abs, regs) |= STORKEY_REF | STORKEY_CHANGE; /* Retrieve the TOD clock value */ etod_clock(regs, &ETOD, ETOD_extended); /* Get processor time(s) and leave out non-CPU processes and * threads */ for(i = 0; i < sysblk.maxcpu; ++i) { if (IS_CPU_ONLINE(i)) { /* Get CPU times in microseconds */ getrusage((int)sysblk.cputid[i], &usage); uCPU[i] = timeval2us(&usage.ru_utime); tCPU[i] = uCPU[i] + timeval2us(&usage.ru_stime); } } memset(hdrinfo, 0, sizeof(DIAG204_HDR)); hdrinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrinfo->flags = DIAG204_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrinfo->physcpu,sysblk.cpus); STORE_HW(hdrinfo->offown,sizeof(DIAG204_HDR)); STORE_DW(hdrinfo->diagstck,ETOD2tod(ETOD)); /* hercules partition */ partinfo = (DIAG204_PART*)(hdrinfo + 1); memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = sysblk.lparnum; /* Hercules partition */ partinfo->virtcpu = sysblk.cpus; get_lparname(partinfo->partname); /* hercules cpu's */ cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index=sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); STORE_DW(cpuinfo->totdispatch,tCPU[i]); STORE_DW(cpuinfo->effdispatch, uCPU[i]); cpuinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* LPAR management */ /* FIXME: This section should report on the real CPUs, appearing * and transformed for reporting purposes. This should * also be properly reflected in STSI information. */ partinfo = (DIAG204_PART*)cpuinfo; memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = 0; /* Physical machine */ partinfo->virtcpu = sysblk.cpus; memcpy(partinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index = sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); STORE_DW(cpuinfo->totdispatch, tCPU[i]); STORE_DW(cpuinfo->effdispatch, uCPU[i]); cpuinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #if defined(FEATURE_EXTENDED_DIAG204) /* Extended subcode 5 returns the size of the data areas provided by extended subcodes 6 and 7 */ case 0x00010005: i = sizeof(DIAG204_X_HDR) + ((sizeof(DIAG204_X_PART) + (sysblk.maxcpu * sizeof(DIAG204_X_PART_CPU))) * 2); regs->GR_L(r2+1) = (i + PAGEFRAME_BYTEMASK) / PAGEFRAME_PAGESIZE; regs->GR_L(r2) = 0; break; /* Provide extended information */ case 0x00010006: /* We fall through as we do not have any secondary cpus (that we know of) */ /* Provide extended information, including information about secondary CPUs */ case 0x00010007: /* Program check if RMF data is not on a page boundary */ if ( (regs->GR_L(r1) & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Obtain absolute address of main storage block, check protection, and set reference and change bits */ hdrxinfo = (DIAG204_X_HDR*)MADDR (GR_A(r1,regs), r1, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Retrieve the TOD clock value */ etod_clock(regs, &ETOD, ETOD_extended); /* Get processor time(s) and leave out non-CPU processes and * threads */ for(i = 0; i < sysblk.maxcpu; ++i) { if (IS_CPU_ONLINE(i)) { /* Get CPU times in microseconds */ getrusage((int)sysblk.cputid[i], &usage); oCPU[i] = etod2us(ETOD.high - regs->tod_epoch - sysblk.cpucreateTOD[i]); uCPU[i] = timeval2us(&usage.ru_utime); tCPU[i] = uCPU[i] + timeval2us(&usage.ru_stime); wCPU[i] = tCPU[i] - uCPU[i]; } } memset(hdrxinfo, 0, sizeof(DIAG204_X_HDR)); hdrxinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrxinfo->flags = DIAG204_X_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrxinfo->physcpu,sysblk.cpus); STORE_HW(hdrxinfo->offown,sizeof(DIAG204_X_HDR)); STORE_DW(hdrxinfo->diagstck1,ETOD.high); STORE_DW(hdrxinfo->diagstck2,ETOD.low); /* hercules partition */ partxinfo = (DIAG204_X_PART*)(hdrxinfo + 1); memset(partxinfo, 0, sizeof(DIAG204_PART)); partxinfo->partnum = sysblk.lparnum; /* Hercules partition */ partxinfo->virtcpu = sysblk.cpus; get_lparname(partxinfo->partname); get_sysname(partxinfo->cpcname); get_systype(partxinfo->osname); STORE_DW(partxinfo->cssize,sysblk.mainsize); STORE_DW(partxinfo->essize,sysblk.xpndsize); get_sysplex(partxinfo->gr_name); /* hercules cpu's */ cpuxinfo = (DIAG204_X_PART_CPU*)(partxinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); STORE_DW(cpuxinfo->totdispatch, tCPU[i]); STORE_DW(cpuxinfo->effdispatch, uCPU[i]); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, oCPU[i]); STORE_DW(cpuxinfo->waittime, wCPU[i]); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* LPAR management */ /* FIXME: This section should report on the real CPUs, appearing * and transformed for reporting purposes. This should * also be properly reflected in STSI information. */ partxinfo = (DIAG204_X_PART*)cpuxinfo; memset(partxinfo, 0, sizeof(DIAG204_X_PART)); partxinfo->partnum = 0; /* Physical machine */ partxinfo->virtcpu = sysblk.cpus; memcpy(partxinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ cpuxinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); STORE_DW(cpuxinfo->totdispatch, tCPU[i]); STORE_DW(cpuxinfo->effdispatch, uCPU[i]); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, oCPU[i]); STORE_DW(cpuxinfo->waittime, wCPU[i]); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ default: PTT_ERR("*DIAG204",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->GR_L(r2) = 4; } /*switch(regs->GR_L(r2))*/ } /* end function diag204_call */
void ARCH_DEP(sync_mck_interrupt) (REGS *regs) { int rc; /* Return code */ PSA *psa; /* -> Prefixed storage area */ U64 mcic = MCIC_P | /* Instruction processing damage */ MCIC_WP | MCIC_MS | MCIC_PM | MCIC_IA | #ifdef FEATURE_HEXADECIMAL_FLOATING_POINT MCIC_FP | #endif /*FEATURE_HEXADECIMAL_FLOATING_POINT*/ MCIC_GR | MCIC_CR | MCIC_ST | #ifdef FEATURE_ACCESS_REGISTERS MCIC_AR | #endif /*FEATURE_ACCESS_REGISTERS*/ #if defined(FEATURE_ESAME) && defined(FEATURE_EXTENDED_TOD_CLOCK) MCIC_PR | #endif /*defined(FEATURE_ESAME) && defined(FEATURE_EXTENDED_TOD_CLOCK)*/ #if defined(FEATURE_BINARY_FLOATING_POINT) MCIC_XF | #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ MCIC_CT | MCIC_CC ; U32 xdmg = 0; RADR fsta = 0; /* Release intlock if held */ if (regs->cpuad == sysblk.intowner) RELEASE_INTLOCK(regs); /* Release mainlock if held */ if (regs->cpuad == sysblk.mainowner) RELEASE_MAINLOCK(regs); /* Exit SIE when active */ #if defined(FEATURE_INTERPRETIVE_EXECUTION) if(regs->sie_active) ARCH_DEP(sie_exit) (regs, SIE_HOST_INTERRUPT); #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ /* Set the main storage reference and change bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Point to the PSA in main storage */ psa = (void*)(regs->mainstor + regs->PX); /* Store registers in machine check save area */ ARCH_DEP(store_status) (regs, regs->PX); #if !defined(FEATURE_ESAME) // ZZ /* Set the extended logout area to zeros */ memset(psa->storepsw, 0, 16); #endif /* Store the machine check interrupt code at PSA+232 */ STORE_DW(psa->mckint, mcic); /* Trace the machine check interrupt */ if (CPU_STEPPING_OR_TRACING(regs, 0)) #if defined(_FEATURE_SIE) WRMSG (HHC00824, "I", regs->sie_active ? "IE" : PTYPSTR(regs->cpuad), regs->sie_active ? regs->guestregs->cpuad : regs->cpuad, mcic); #else WRMSG (HHC00824, "I", PTYPSTR(regs->cpuad), regs->cpuad, mcic); #endif /* Store the external damage code at PSA+244 */ STORE_FW(psa->xdmgcode, xdmg); #if defined(FEATURE_ESAME) /* Store the failing storage address at PSA+248 */ STORE_DW(psa->mcstorad, fsta); #else /*!defined(FEATURE_ESAME)*/ /* Store the failing storage address at PSA+248 */ STORE_FW(psa->mcstorad, fsta); #endif /*!defined(FEATURE_ESAME)*/ /* Store current PSW at PSA+X'30' */ ARCH_DEP(store_psw) ( regs, psa->mckold ); /* Load new PSW from PSA+X'70' */ rc = ARCH_DEP(load_psw) ( regs, psa->mcknew ); if ( rc ) ARCH_DEP(program_interrupt) (regs, rc); } /* end function sync_mck_interrupt */
/*-------------------------------------------------------------------*/ int ARCH_DEP(load_ipl) (U16 lcss, U16 devnum, int cpu, int clear) { REGS *regs; /* -> Regs */ DEVBLK *dev; /* -> Device control block */ int i; /* Array subscript */ BYTE unitstat; /* IPL device unit status */ BYTE chanstat; /* IPL device channel status */ /* Get started */ if (ARCH_DEP(common_load_begin) (cpu, clear) != 0) return -1; /* The actual IPL proper starts here... */ regs = sysblk.regs[cpu]; /* Point to IPL CPU's registers */ /* Point to the device block for the IPL device */ dev = find_device_by_devnum (lcss,devnum); if (dev == NULL) { logmsg (_("HHCCP027E Device %4.4X not in configuration%s\n"), devnum, (sysblk.arch_mode == ARCH_370 ? " or not conneceted to channelset" : "")); HDC1(debug_cpu_state, regs); return -1; } #if defined(OPTION_IPLPARM) if(sysblk.haveiplparm) { for(i=0;i<16;i++) { regs->GR_L(i)=fetch_fw(&sysblk.iplparmstring[i*4]); } sysblk.haveiplparm=0; } #endif /* Set Main Storage Reference and Update bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); sysblk.main_clear = sysblk.xpnd_clear = 0; /* Build the IPL CCW at location 0 */ regs->psa->iplpsw[0] = 0x02; /* CCW command = Read */ regs->psa->iplpsw[1] = 0; /* Data address = zero */ regs->psa->iplpsw[2] = 0; regs->psa->iplpsw[3] = 0; regs->psa->iplpsw[4] = CCW_FLAGS_CC | CCW_FLAGS_SLI; /* CCW flags */ regs->psa->iplpsw[5] = 0; /* Reserved byte */ regs->psa->iplpsw[6] = 0; /* Byte count = 24 */ regs->psa->iplpsw[7] = 24; /* Enable the subchannel for the IPL device */ dev->pmcw.flag5 |= PMCW5_E; /* Build the operation request block */ /*@IWZ*/ memset (&dev->orb, 0, sizeof(ORB)); /*@IWZ*/ dev->busy = 1; RELEASE_INTLOCK(NULL); /* Execute the IPL channel program */ ARCH_DEP(execute_ccw_chain) (dev); OBTAIN_INTLOCK(NULL); /* Clear the interrupt pending and device busy conditions */ obtain_lock (&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->attnioint); release_lock(&sysblk.iointqlk); dev->busy = 0; dev->scsw.flag2 = 0; dev->scsw.flag3 = 0; /* Check that load completed normally */ #ifdef FEATURE_S370_CHANNEL unitstat = dev->csw[4]; chanstat = dev->csw[5]; #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM unitstat = dev->scsw.unitstat; chanstat = dev->scsw.chanstat; #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) { logmsg (_("HHCCP029E %s mode IPL failed: CSW status=%2.2X%2.2X\n" " Sense="), get_arch_mode_string(regs), unitstat, chanstat); for (i=0; i < (int)dev->numsense; i++) { logmsg ("%2.2X", dev->sense[i]); if ((i & 3) == 3) logmsg(" "); } logmsg ("\n"); HDC1(debug_cpu_state, regs); return -1; } #ifdef FEATURE_S370_CHANNEL /* Test the EC mode bit in the IPL PSW */ if (regs->psa->iplpsw[1] & 0x08) { /* In EC mode, store device address at locations 184-187 */ STORE_FW(regs->psa->ioid, dev->devnum); } else { /* In BC mode, store device address at locations 2-3 */ STORE_HW(regs->psa->iplpsw + 2, dev->devnum); } #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Set LPUM */ dev->pmcw.lpum = 0x80; STORE_FW(regs->psa->ioid, (dev->ssid<<16)|dev->subchan); /* Store zeroes at locations 188-191 */ memset (regs->psa->ioparm, 0, 4); #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Save IPL device number, cpu number and lcss */ sysblk.ipldev = devnum; sysblk.iplcpu = regs->cpuad; sysblk.ipllcss = lcss; /* Finish up... */ return ARCH_DEP(common_load_finish) (regs); } /* end function load_ipl */
/*-------------------------------------------------------------------*/ void ARCH_DEP(store_status) (REGS *ssreg, RADR aaddr) { int i; /* Array subscript */ PSA *sspsa; /* -> Store status area */ /* Set reference and change bits */ STORAGE_KEY(aaddr, ssreg) |= (STORKEY_REF | STORKEY_CHANGE); #if defined(FEATURE_ESAME) /* The ESAME PSA is two pages in size */ if(!aaddr) STORAGE_KEY(aaddr + 4096, ssreg) |= (STORKEY_REF | STORKEY_CHANGE); #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /* For store status at address, we must adjust the PSA offset */ /* ZZ THIS TEST IS NOT CONCLUSIVE */ if(aaddr != 0 && aaddr != ssreg->PX) aaddr -= 512 + 4096 ; #endif aaddr &= 0x7FFFFE00; /* Point to the PSA into which status is to be stored */ sspsa = (void*)(ssreg->mainstor + aaddr); /* Store CPU timer in bytes 216-223 */ STORE_DW(sspsa->storeptmr, cpu_timer(ssreg)); /* Store clock comparator in bytes 224-231 */ #if defined(FEATURE_ESAME) STORE_DW(sspsa->storeclkc, ssreg->clkc); #else /*defined(FEATURE_ESAME)*/ STORE_DW(sspsa->storeclkc, ssreg->clkc << 8); #endif /*defined(FEATURE_ESAME)*/ /* Store PSW in bytes 256-263 */ ARCH_DEP(store_psw) (ssreg, sspsa->storepsw); /* Store prefix register in bytes 264-267 */ STORE_FW(sspsa->storepfx,ssreg->PX); #if defined(FEATURE_ESAME) /* Store Floating Point Control Register */ STORE_FW(sspsa->storefpc,ssreg->fpc); /* Store TOD Programable register */ STORE_FW(sspsa->storetpr,ssreg->todpr); #endif /*defined(FEATURE_ESAME)*/ #if defined(_900) /* Only store the arch mode indicator for a PSA type store status */ if(!aaddr) #if defined(FEATURE_ESAME) sspsa->arch = 1; #else /*defined(FEATURE_ESAME)*/ sspsa->arch = 0; #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(_900)*/ /* Store access registers in bytes 288-351 */ for (i = 0; i < 16; i++) STORE_FW(sspsa->storear[i],ssreg->AR(i)); /* Store floating-point registers in bytes 352-383 */ #if defined(FEATURE_ESAME) for (i = 0; i < 32; i++) #else /*!defined(FEATURE_ESAME)*/ for (i = 0; i < 8; i++) #endif /*!defined(FEATURE_ESAME)*/ STORE_FW(sspsa->storefpr[i],ssreg->fpr[i]); /* Store general-purpose registers in bytes 384-447 */ for (i = 0; i < 16; i++) STORE_W(sspsa->storegpr[i],ssreg->GR(i)); /* Store control registers in bytes 448-511 */ for (i = 0; i < 16; i++) STORE_W(sspsa->storecr[i],ssreg->CR(i)); } /* end function store_status */
/*-------------------------------------------------------------------*/ static void ARCH_DEP(alter_display_virt) (char *opnd, REGS *regs) { U64 saddr, eaddr; /* Range start/end addresses */ U64 maxadr; /* Highest virt storage addr */ VADR vaddr; /* Virtual storage address */ RADR raddr; /* Real storage address */ RADR aaddr; /* Absolute storage address */ int stid; /* Segment table indication */ int len; /* Number of bytes to alter */ int i; /* Loop counter */ int n; /* Number of bytes in buffer */ int arn = 0; /* Access register number */ U16 xcode; /* Exception code */ BYTE newval[32]; /* Storage alteration value */ char buf[100]; /* Message buffer */ /* Set limit for address range */ #if defined(FEATURE_ESAME) maxadr = 0xFFFFFFFFFFFFFFFFULL; #else /*!defined(FEATURE_ESAME)*/ maxadr = 0x7FFFFFFF; #endif /*!defined(FEATURE_ESAME)*/ while((opnd && *opnd != '\0') && (*opnd == ' ' || *opnd == '\t')) opnd++; switch(toupper(*opnd)) { case 'P': /* primary */ arn = USE_PRIMARY_SPACE; opnd++; break; case 'S': /* secondary */ arn = USE_SECONDARY_SPACE; opnd++; break; case 'H': /* home */ arn = USE_HOME_SPACE; opnd++; break; } /* Parse the range or alteration operand */ len = parse_range (opnd, maxadr, &saddr, &eaddr, newval); if (len < 0) return; vaddr = saddr; /* Alter virtual storage */ if (len > 0 && ARCH_DEP(virt_to_abs) (&raddr, &stid, vaddr, arn, regs, ACCTYPE_LRA) == 0 && ARCH_DEP(virt_to_abs) (&raddr, &stid, eaddr, arn, regs, ACCTYPE_LRA) == 0) { for (i = 0; i < len && raddr+i <= regs->mainlim; i++) { ARCH_DEP(virt_to_abs) (&raddr, &stid, vaddr+i, arn, regs, ACCTYPE_LRA); aaddr = APPLY_PREFIXING (raddr, regs->PX); regs->mainstor[aaddr] = newval[i]; STORAGE_KEY(aaddr, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* end for(i) */ } /* Display virtual storage */ for (i = 0; i < 999 && vaddr <= eaddr; i++) { if (i == 0 || (vaddr & PAGEFRAME_BYTEMASK) < 16) { xcode = ARCH_DEP(virt_to_abs) (&raddr, &stid, vaddr, arn, regs, ACCTYPE_LRA); n = sprintf (buf, "V:"F_VADR" ", vaddr); if (REAL_MODE(®s->psw)) n += sprintf (buf+n, "(dat off)"); else if (stid == TEA_ST_PRIMARY) n += sprintf (buf+n, "(primary)"); else if (stid == TEA_ST_SECNDRY) n += sprintf (buf+n, "(secondary)"); else if (stid == TEA_ST_HOME) n += sprintf (buf+n, "(home)"); else n += sprintf (buf+n, "(AR%2.2d)", arn); if (xcode == 0) n += sprintf (buf+n, " R:"F_RADR, raddr); logmsg ("%s\n", buf); } ARCH_DEP(display_virt) (regs, vaddr, buf, arn, ACCTYPE_LRA); logmsg ("%s\n", buf); vaddr += 16; } /* end for(i) */ } /* end function alter_display_virt */
/*-------------------------------------------------------------------*/ static void ARCH_DEP(hwl_loadfile)(SCCB_HWL_BK *hwl_bk) { CREG sto; U32 size; int fd; fd = open (hwl_fn[hwl_bk->file], O_RDONLY|O_BINARY); if (fd < 0) { logmsg (_("HHCHL002I %s open error: %s\n"), hwl_fn[hwl_bk->file], strerror(errno)); return; } // else // logmsg(_("HHCHL004I Loading %s\n"),hwl_fn[hwl_bk->file]); FETCH_FW(size,hwl_bk->size); /* Segment Table Origin */ FETCH_DW(sto,hwl_bk->sto); #if defined(FEATURE_ESAME) sto &= ASCE_TO; #else /*!defined(FEATURE_ESAME)*/ sto &= STD_STO; #endif /*!defined(FEATURE_ESAME)*/ for( ; ; sto += sizeof(sto)) { #if defined(FEATURE_ESAME) DBLWRD *ste; #else /*!defined(FEATURE_ESAME)*/ FWORD *ste; #endif /*!defined(FEATURE_ESAME)*/ CREG pto, pti; /* Fetch segment table entry and calculate Page Table Origin */ if( sto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) ste = (DBLWRD*)(sysblk.mainstor + sto); #else /*!defined(FEATURE_ESAME)*/ ste = (FWORD*)(sysblk.mainstor + sto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pto, ste); if( pto & SEGTAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pto &= ZSEGTAB_PTO; #else /*!defined(FEATURE_ESAME)*/ pto &= SEGTAB_PTO; #endif /*!defined(FEATURE_ESAME)*/ for(pti = 0; pti < 256 ; pti++, pto += sizeof(pto)) { #if defined(FEATURE_ESAME) DBLWRD *pte; #else /*!defined(FEATURE_ESAME)*/ FWORD *pte; #endif /*!defined(FEATURE_ESAME)*/ CREG pgo; BYTE *page; /* Fetch Page Table Entry to get page origin */ if( pto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) pte = (DBLWRD*)(sysblk.mainstor + pto); #else /*!defined(FEATURE_ESAME)*/ pte = (FWORD*)(sysblk.mainstor + pto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pgo, pte); if( pgo & PAGETAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pgo &= ZPGETAB_PFRA; #else /*!defined(FEATURE_ESAME)*/ pgo &= PAGETAB_PFRA; #endif /*!defined(FEATURE_ESAME)*/ /* Read page into main storage */ if( pgo >= sysblk.mainsize) goto eof; page = sysblk.mainstor + pgo; if( !(size--) || !read(fd, page, STORAGE_KEY_PAGESIZE) ) goto eof; STORAGE_KEY(pgo, &sysblk) |= (STORKEY_REF|STORKEY_CHANGE); } } eof: close(fd); }
/*-------------------------------------------------------------------*/ void ARCH_DEP(diag204_call) (int r1, int r2, REGS *regs) { DIAG204_HDR *hdrinfo; /* Header */ DIAG204_PART *partinfo; /* Partition info */ DIAG204_PART_CPU *cpuinfo; /* CPU info */ #if defined(FEATURE_EXTENDED_DIAG204) DIAG204_X_HDR *hdrxinfo; /* Header */ DIAG204_X_PART *partxinfo; /* Partition info */ DIAG204_X_PART_CPU *cpuxinfo; /* CPU info */ U64 tdis; #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ RADR abs; /* abs addr of data area */ U64 dreg; /* work doubleword */ int i; /* loop counter */ struct rusage usage; /* RMF type data */ static U64 diag204tod; /* last diag204 tod */ #if defined(FEATURE_PHYSICAL_DIAG204) static BYTE physical[8] = {0xD7,0xC8,0xE8,0xE2,0xC9,0xC3,0xC1,0xD3}; /* PHYSICAL */ #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ /* Test DIAG204 command word */ switch (regs->GR_L(r2)) { case 0x04: abs = APPLY_PREFIXING (GR_A(r1,regs), regs->PX); /* Program check if RMF data is not on a page boundary */ if ( (abs & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if RMF data area is outside main storage */ if ( abs > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Point to DIAG 204 data area */ hdrinfo = (DIAG204_HDR*)(regs->mainstor + abs); /* Mark page referenced */ STORAGE_KEY(abs, regs) |= STORKEY_REF | STORKEY_CHANGE; /* save last diag204 tod */ dreg = diag204tod; /* Retrieve the TOD clock value and shift out the epoch */ diag204tod = tod_clock(regs) << 8; memset(hdrinfo, 0, sizeof(DIAG204_HDR)); hdrinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrinfo->flags = DIAG204_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrinfo->physcpu,sysblk.cpus); STORE_HW(hdrinfo->offown,sizeof(DIAG204_HDR)); STORE_DW(hdrinfo->diagstck,dreg); /* hercules partition */ partinfo = (DIAG204_PART*)(hdrinfo + 1); memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = 1; /* Hercules partition */ partinfo->virtcpu = sysblk.cpus; get_lparname(partinfo->partname); /* hercules cpu's */ getrusage(RUSAGE_SELF,&usage); cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index=sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); dreg = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->totdispatch,dreg); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->effdispatch,dreg); cpuinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* lpar management */ getrusage(RUSAGE_CHILDREN,&usage); partinfo = (DIAG204_PART*)cpuinfo; memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = 0; /* Physical machine */ partinfo->virtcpu = sysblk.cpus; memcpy(partinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ getrusage(RUSAGE_SELF,&usage); cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index = sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); dreg = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->totdispatch,dreg); dreg = (U64)(usage.ru_utime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->effdispatch,dreg); cpuinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #if defined(FEATURE_EXTENDED_DIAG204) /* Extended subcode 5 returns the size of the data areas provided by extended subcodes 6 and 7 */ case 0x00010005: i = sizeof(DIAG204_X_HDR) + ((sizeof(DIAG204_X_PART) + (sysblk.maxcpu * sizeof(DIAG204_X_PART_CPU))) * 2); regs->GR_L(r2+1) = (i + PAGEFRAME_BYTEMASK) / PAGEFRAME_PAGESIZE; regs->GR_L(r2) = 0; break; /* Provide extended information */ case 0x00010006: /* We fall through as we do not have any secondary cpus (that we know of) */ /* Provide extended information, including information about secondary CPUs */ case 0x00010007: /* Program check if RMF data is not on a page boundary */ if ( (regs->GR_L(r1) & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Obtain absolute address of main storage block, check protection, and set reference and change bits */ hdrxinfo = (DIAG204_X_HDR*)MADDR (GR_A(r1,regs), r1, regs, ACCTYPE_WRITE, regs->psw.pkey); /* save last diag204 tod */ dreg = diag204tod; /* Retrieve the TOD clock value and shift out the epoch */ diag204tod = tod_clock(regs) << 8; memset(hdrxinfo, 0, sizeof(DIAG204_X_HDR)); hdrxinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrxinfo->flags = DIAG204_X_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrxinfo->physcpu,sysblk.cpus); STORE_HW(hdrxinfo->offown,sizeof(DIAG204_X_HDR)); STORE_DW(hdrxinfo->diagstck1,(dreg >> 8)); STORE_DW(hdrxinfo->diagstck2,( 0x0000000001000000ULL | (regs->cpuad << 16) | regs->todpr)); /* hercules partition */ partxinfo = (DIAG204_X_PART*)(hdrxinfo + 1); memset(partxinfo, 0, sizeof(DIAG204_PART)); partxinfo->partnum = 1; /* Hercules partition */ partxinfo->virtcpu = sysblk.cpus; get_lparname(partxinfo->partname); get_sysname(partxinfo->cpcname); get_systype(partxinfo->osname); STORE_DW(partxinfo->cssize,sysblk.mainsize); STORE_DW(partxinfo->essize,sysblk.xpndsize); get_sysplex(partxinfo->gr_name); /* hercules cpu's */ getrusage(RUSAGE_SELF,&usage); cpuxinfo = (DIAG204_X_PART_CPU*)(partxinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); tdis = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; tdis = (tdis + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; tdis <<= 12; STORE_DW(cpuxinfo->totdispatch,tdis); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuxinfo->effdispatch,dreg); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, diag204tod - sysblk.todstart); STORE_DW(cpuxinfo->waittime, (diag204tod - sysblk.todstart) - tdis); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* lpar management */ partxinfo = (DIAG204_X_PART*)cpuxinfo; memset(partxinfo, 0, sizeof(DIAG204_X_PART)); partxinfo->partnum = 0; /* Physical machine */ partxinfo->virtcpu = sysblk.cpus; memcpy(partxinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ getrusage(RUSAGE_CHILDREN,&usage); cpuxinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); tdis = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; tdis = (tdis + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; tdis <<= 12; STORE_DW(cpuxinfo->totdispatch,tdis); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuxinfo->effdispatch,dreg); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, diag204tod - sysblk.todstart); STORE_DW(cpuxinfo->waittime, (diag204tod - sysblk.todstart) - tdis); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ default: PTT(PTT_CL_ERR,"*DIAG204",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->GR_L(r2) = 4; } /*switch(regs->GR_L(r2))*/ } /* end function diag204_call */
/*-------------------------------------------------------------------*/ int ARCH_DEP(load_ipl) (U16 lcss, U16 devnum, int cpu, int clear) { REGS *regs; /* -> Regs */ DEVBLK *dev; /* -> Device control block */ int i; /* Array subscript */ BYTE unitstat; /* IPL device unit status */ BYTE chanstat; /* IPL device channel status */ int rc; /* Get started */ if ((rc = ARCH_DEP(common_load_begin) (cpu, clear)) ) return rc; /* Ensure CPU is online */ if (!IS_CPU_ONLINE(cpu)) { char buf[80]; MSGBUF(buf, "CP%02.2X Offline", devnum); WRMSG (HHC00810, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu, buf); return -1; } /* The actual IPL proper starts here... */ regs = sysblk.regs[cpu]; /* Point to IPL CPU's registers */ /* Point to the device block for the IPL device */ dev = find_device_by_devnum (lcss,devnum); if (dev == NULL) { char buf[80]; MSGBUF(buf, "device %4.4X not found", devnum); WRMSG (HHC00810, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu, buf); HDC1(debug_cpu_state, regs); return -1; } if(sysblk.haveiplparm) { for(i=0;i<16;i++) { regs->GR_L(i)=fetch_fw(&sysblk.iplparmstring[i*4]); } sysblk.haveiplparm=0; } /* Set Main Storage Reference and Update bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); sysblk.main_clear = sysblk.xpnd_clear = 0; /* Build the IPL CCW at location 0 */ regs->psa->iplpsw[0] = 0x02; /* CCW command = Read */ regs->psa->iplpsw[1] = 0; /* Data address = zero */ regs->psa->iplpsw[2] = 0; regs->psa->iplpsw[3] = 0; regs->psa->iplpsw[4] = CCW_FLAGS_CC | CCW_FLAGS_SLI; /* CCW flags */ regs->psa->iplpsw[5] = 0; /* Reserved byte */ regs->psa->iplpsw[6] = 0; /* Byte count = 24 */ regs->psa->iplpsw[7] = 24; /* Enable the subchannel for the IPL device */ dev->pmcw.flag5 |= PMCW5_E; /* Build the operation request block */ /*@IWZ*/ memset (&dev->orb, 0, sizeof(ORB)); /*@IWZ*/ dev->busy = 1; RELEASE_INTLOCK(NULL); /* Execute the IPL channel program */ ARCH_DEP(execute_ccw_chain) (dev); OBTAIN_INTLOCK(NULL); /* Clear the interrupt pending and device busy conditions */ obtain_lock (&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->attnioint); release_lock(&sysblk.iointqlk); dev->busy = 0; dev->scsw.flag2 = 0; dev->scsw.flag3 = 0; /* Check that load completed normally */ unitstat = dev->scsw.unitstat; chanstat = dev->scsw.chanstat; if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) { char buf[80]; char buf2[16]; memset(buf,0,sizeof(buf)); for (i=0; i < (int)dev->numsense; i++) { MSGBUF(buf2, "%2.2X", dev->sense[i]); strlcat(buf, buf2, sizeof(buf) ); if ((i & 3) == 3) strlcat(buf, " ", sizeof(buf)); } { char buffer[256]; MSGBUF(buffer, "architecture mode %s, csw status %2.2X%2.2X, sense %s", get_arch_mode_string((REGS *)0), unitstat, chanstat, buf); WRMSG (HHC00828, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu, buffer); } HDC1(debug_cpu_state, regs); return -1; } #ifdef FEATURE_S370_CHANNEL /* Test the EC mode bit in the IPL PSW */ if (regs->psa->iplpsw[1] & 0x08) { /* In EC mode, store device address at locations 184-187 */ STORE_FW(regs->psa->ioid, dev->devnum); } else { /* In BC mode, store device address at locations 2-3 */ STORE_HW(regs->psa->iplpsw + 2, dev->devnum); } #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Set LPUM */ dev->pmcw.lpum = 0x80; STORE_FW(regs->psa->ioid, (dev->ssid<<16)|dev->subchan); /* Store zeroes at locations 188-191 */ memset (regs->psa->ioparm, 0, 4); #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Save IPL device number, cpu number and lcss */ sysblk.ipldev = devnum; sysblk.iplcpu = regs->cpuad; sysblk.ipllcss = lcss; sysblk.ipled = TRUE; /* Finish up... */ return ARCH_DEP(common_load_finish) (regs); } /* end function load_ipl */
/*-------------------------------------------------------------------*/ void ARCH_DEP(perform_external_interrupt) (REGS *regs) { PSA *psa; /* -> Prefixed storage area */ U16 cpuad; /* Originating CPU address */ #if defined(FEATURE_VM_BLOCKIO) #if defined(FEATURE_ESAME) RADR servpadr; /* Address of 64-bit block I/O interrupt */ #endif U16 servcode; /* Service Signal or Block I/O Interrupt code */ #endif /* defined(FEATURE_VM_BLOCKIO) */ /* External interrupt if console interrupt key was depressed */ if ( OPEN_IC_INTKEY(regs) && !SIE_MODE(regs) ) { WRMSG (HHC00840, "I"); /* Reset interrupt key pending */ OFF_IC_INTKEY; /* Generate interrupt key interrupt */ ARCH_DEP(external_interrupt) (EXT_INTERRUPT_KEY_INTERRUPT, regs); } /* External interrupt if malfunction alert is pending */ if (OPEN_IC_MALFALT(regs)) { /* Find first CPU which generated a malfunction alert */ for (cpuad = 0; regs->malfcpu[cpuad] == 0; cpuad++) { if (cpuad >= sysblk.maxcpu) { OFF_IC_MALFALT(regs); return; } } /* end for(cpuad) */ // /*debug*/ logmsg (_("External interrupt: Malfuction Alert from CPU %d\n"), // /*debug*/ cpuad); /* Reset the indicator for the CPU which was found */ regs->malfcpu[cpuad] = 0; /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,cpuad); /* Reset emergency signal pending flag if there are no other CPUs which generated emergency signal */ OFF_IC_MALFALT(regs); while (++cpuad < sysblk.maxcpu) { if (regs->malfcpu[cpuad]) { ON_IC_MALFALT(regs); break; } } /* end while */ /* Generate emergency signal interrupt */ ARCH_DEP(external_interrupt) (EXT_MALFUNCTION_ALERT_INTERRUPT, regs); } /* External interrupt if emergency signal is pending */ if (OPEN_IC_EMERSIG(regs)) { /* Find first CPU which generated an emergency signal */ for (cpuad = 0; regs->emercpu[cpuad] == 0; cpuad++) { if (cpuad >= sysblk.maxcpu) { OFF_IC_EMERSIG(regs); return; } } /* end for(cpuad) */ // /*debug*/ logmsg (_("External interrupt: Emergency Signal from CPU %d\n"), // /*debug*/ cpuad); /* Reset the indicator for the CPU which was found */ regs->emercpu[cpuad] = 0; /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,cpuad); /* Reset emergency signal pending flag if there are no other CPUs which generated emergency signal */ OFF_IC_EMERSIG(regs); while (++cpuad < sysblk.maxcpu) { if (regs->emercpu[cpuad]) { ON_IC_EMERSIG(regs); break; } } /* end while */ /* Generate emergency signal interrupt */ ARCH_DEP(external_interrupt) (EXT_EMERGENCY_SIGNAL_INTERRUPT, regs); } /* External interrupt if external call is pending */ if (OPEN_IC_EXTCALL(regs)) { // /*debug*/logmsg (_("External interrupt: External Call from CPU %d\n"), // /*debug*/ regs->extccpu); /* Reset external call pending */ OFF_IC_EXTCALL(regs); /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,regs->extccpu); /* Generate external call interrupt */ ARCH_DEP(external_interrupt) (EXT_EXTERNAL_CALL_INTERRUPT, regs); } /* External interrupt if TOD clock exceeds clock comparator */ if ( tod_clock(regs) > regs->clkc && OPEN_IC_CLKC(regs) ) { if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00841, "I"); } ARCH_DEP(external_interrupt) (EXT_CLOCK_COMPARATOR_INTERRUPT, regs); } /* External interrupt if CPU timer is negative */ if ( CPU_TIMER(regs) < 0 && OPEN_IC_PTIMER(regs) ) { if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00842, "I", CPU_TIMER(regs) << 8); } ARCH_DEP(external_interrupt) (EXT_CPU_TIMER_INTERRUPT, regs); } /* External interrupt if interval timer interrupt is pending */ #if defined(FEATURE_INTERVAL_TIMER) if (OPEN_IC_ITIMER(regs) #if defined(_FEATURE_SIE) && !(SIE_STATB(regs, M, ITMOF)) #endif /*defined(_FEATURE_SIE)*/ ) { if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00843, "I"); } OFF_IC_ITIMER(regs); ARCH_DEP(external_interrupt) (EXT_INTERVAL_TIMER_INTERRUPT, regs); } #if defined(FEATURE_ECPSVM) if ( OPEN_IC_ECPSVTIMER(regs) ) { OFF_IC_ECPSVTIMER(regs); ARCH_DEP(external_interrupt) (EXT_VINTERVAL_TIMER_INTERRUPT,regs); } #endif /*FEATURE_ECPSVM*/ #endif /*FEATURE_INTERVAL_TIMER*/ /* External interrupt if service signal is pending */ if ( OPEN_IC_SERVSIG(regs) && !SIE_MODE(regs) ) { #if defined(FEATURE_VM_BLOCKIO) /* Note: Both Block I/O and Service Signal are enabled by the */ /* the same CR0 bit. Hence they are handled in the same code */ switch(sysblk.servcode) { case EXT_BLOCKIO_INTERRUPT: /* VM Block I/O Interrupt */ if (sysblk.biodev->ccwtrace) { WRMSG (HHC00844, "I", SSID_TO_LCSS(sysblk.biodev->ssid), sysblk.biodev->devnum, sysblk.servcode, sysblk.bioparm, sysblk.biostat, sysblk.biosubcd ); } servcode = EXT_BLOCKIO_INTERRUPT; #if defined(FEATURE_ESAME) /* Real address used to store the 64-bit interrupt parameter */ #define VM_BLOCKIO_INT_PARM 0x11B8 if (sysblk.biosubcd == 0x07) { /* 8-byte interrupt parm */ if (CPU_STEPPING_OR_TRACING_ALL) { char buf[40]; MSGBUF(buf, "%16.16X", (unsigned) sysblk.bioparm); WRMSG (HHC00845,"I", buf); } /* Set the main storage reference and change bits */ /* for 64-bit interruption parameter. */ /* Note: This is handled for the first 4K page in */ /* ARCH_DEP(external_interrupt), but not for the */ /* the second 4K page used for the 64-bit interrupt */ /* parameter. */ /* Point to 2nd page of PSA in main storage */ servpadr=APPLY_PREFIXING(VM_BLOCKIO_INT_PARM,regs->PX); STORAGE_KEY(servpadr, regs) |= (STORKEY_REF | STORKEY_CHANGE); #if 0 /* Store the 64-bit interrupt parameter */ logmsg (_("Saving 64-bit Block I/O interrupt parm at " "%16.16X: %16.16X\n"), servpadr, sysblk.bioparm ); #endif STORE_DW(regs->mainstor + servpadr,sysblk.bioparm); psa = (void*)(regs->mainstor + regs->PX); } else { #endif /* defined(FEATURE_ESAME) */ /* 4-byte interrupt parm */ if (CPU_STEPPING_OR_TRACING_ALL) { char buf[40]; MSGBUF(buf, "%8.8X", (U32) sysblk.bioparm); WRMSG (HHC00845,"I", buf); } /* Store Block I/O parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,(U32)sysblk.bioparm); #if defined(FEATURE_ESAME) } #endif /* Store sub-interruption code and status at PSA+X'84' */ STORE_HW(psa->extcpad,(sysblk.biosubcd<<8)|sysblk.biostat); /* Reset interruption data */ sysblk.bioparm = 0; sysblk.biosubcd = 0; sysblk.biostat = 0; break; case EXT_SERVICE_SIGNAL_INTERRUPT: /* Service Signal */ default: servcode = EXT_SERVICE_SIGNAL_INTERRUPT; /* Apply prefixing if the parameter is a storage address */ if ( (sysblk.servparm & SERVSIG_ADDR) ) sysblk.servparm = APPLY_PREFIXING (sysblk.servparm, regs->PX); if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00846,"I", sysblk.servparm); } /* Store service signal parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,sysblk.servparm); } /* end switch(sysblk.servcode) */ /* Reset service parameter */ sysblk.servparm = 0; /* Reset service code */ sysblk.servcode = 0; /* Reset service signal pending */ OFF_IC_SERVSIG; /* Generate service signal interrupt */ ARCH_DEP(external_interrupt) (servcode, regs); #else /* defined(FEATURE_VM_BLOCKIO) */ /* Apply prefixing if the parameter is a storage address */ if ( (sysblk.servparm & SERVSIG_ADDR) ) sysblk.servparm = APPLY_PREFIXING (sysblk.servparm, regs->PX); if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00846,"I", sysblk.servparm); } /* Store service signal parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,sysblk.servparm); /* Reset service parameter */ sysblk.servparm = 0; /* Reset service signal pending */ OFF_IC_SERVSIG; /* Generate service signal interrupt */ ARCH_DEP(external_interrupt) (EXT_SERVICE_SIGNAL_INTERRUPT, regs); #endif /* defined(FEATURE_VM_BLOCKIO) */ } /* end OPEN_IC_SERVSIG(regs) */ } /* end function perform_external_interrupt */