/*-------------------------------------------------------------------*/ 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(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_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 */