SRB – Service Request Block Overview

A Service Request Block (SRB) defines a dispatchable unit of work (Service Routine) in MVS.  A dispatchable unit of work is just a fancy way of saying some code that will be run by the dispatcher.  A SRB as opposed to a Task Control Block is considered a lightweight task.  This simply means it has less overhead associated with creating and dispatching it.  It also means that the capabilities are more limited.  SRB routines always run in supervisor mode.  They may not issue SVC calls and they are nonpreemptiable – meaning a higher priority task cannot preempt them.

SRB routines can be scheduled to run in any Address Space.  This makes them very useful for cross memory access in a pre-XA environment.  This is exactly what we will ultimately do with our SRB routine.  We will schedule it into an address space to allow us to copy local memory into a Common Service Area (CSA) storage (shared memory location).

SRB routines are fairly simple but we do have to be careful since we are writing code that executes in supervisor mode and key zero.  When I was initially testing my SRB code I did manage to crash my MVS system a few times due to simple coding mistakes. Fortunately, with Hercules I can IPL and be back up and running quickly.  It also helps that I am the only user on the system.

A SRB routine is created by allocating some memory to hold the SRB and then using the SCHEDULE macro to schedule it for execution.  The SRB must reside in fixed, commonly-addressable storage.

SRB Control Block

The SRB is defined by the macro IHASRB in SYS1.MACLIB.

SRBSECT  DSECT
SRB      DS    0A
SRBID    DS    CL4                      EBCDIC ACRONYM   FOR SRB
SRBFLNK  DS    A                        FORWARD CHAIN FIELD
SRBASCB  DS    A                        PTR TO ASCB OF ADDRESS SPACE
*                                       SRB IS TO BE DISPATCHED TO
SRBFLC   DS    0CL8                     SRB AREA MOVED TO LOW CORE
SRBCPAFF DS    BL2                      CPU AFFINITY MASK
SRBPASID DS    H                        PURGEDQ ASID IDENTIFIER
SRBPTCB  DS    A                        PURGEDQ TCB IDENTIFIER
SRBEP    DS    A                        ENTRY POINT OF ROUTINE
SRBRMTR  DS    A                        ADDRESS OF RESOURCE MGR RTN
SRBPARM  DS    A                        USER PARAMETER
SRBSAVE  DS    A                        SAVE AREA POINTER
SRBPKF   DS    B                        PROTECT KEY INDICATION
SRBPRIOR DS    B                        PRIORITY LEVEL INDICATION
SRBPSYS  EQU   0                        SYSTEM PRIORITY LEVEL
SRBPNONQ EQU   4                        NON-QUIESCEABLE PRIORITY
         DS    BL2                      RESERVED
         DS    A                        RESERVED
SRBEND   EQU   *                        END OF SRB
SRBSIZE  EQU   SRBEND-SRBSECT           SIZE OF SRB

SRBID is the eyeball identifier for the block and should contain ‘SRB .

SRBFLNK if the forward chain pointer and should be initialized to binary zeros.

SRBASCB is the address of the ASCB for the address space this SRB is to be dispatched into.

SRBCPAFF is a bitmask that indicates which CPUs may dispatch this SRB.  If it is binary zero or all ones the SRB can be dispatched to any CPU.  Since MVS 3.8 usually only runs on single CPU systems we can set it to zeros.

SRBPASID may contain a pointer to the ASCB of the address space associated withthis SRB.  It may be set to zero if SRBPTCB is also zero otherwise it must be specified.

SRBPTCB may contain a pointer to the TCB associated with this SRB.  If it is specified the SRBPASID field must also be set.  If these fields are set and a double failure occurs then the associated TCB will be scheduled for abnormal termination (ABEND).  A double failure occurs when an error has been trapped by a recovery routine and the recovery routine also fails.  Setting this field also allows the SRB to be purged if the associated TCB is terminated.  This field may be set to zero if not needed.

SRBEP is the entry point of the SRB routine.

SRBRMTR is the address of a Resource Manager Termination Routine that is called if the SRB is purged before it is scheduled.  The RMTR is responsible for any cleanup.

SRBPARM is a fullword parameter value that is passed to the SRB routine when it is dispatched.

SRBSAVE is the address of the status save area and must be initialized to zeros.

SRBPKF specifies the PSW protect key for the SRB routine.  The high-order four bits specify the protect key and the low-order four bits must be zero.

SRBPRIOR is the priority of a GLOBAL SRB.  GLOBAL SRBs are dispatched at a higher priority than any address space.  LOCAL SRBs are dispatched at the priority of the address space they run in but at a higher priority than any TCB.  GLOBAL SRBs have an additional priority level that indicates if they are for general system usage or a special priority necessary to quiesce SRBs.  A value of zero indicates a general system SRB.  A value of four indicates a priority of NONQ (nonquiesceable).  We can always set this value to zero.

The additional reserved fields should be set to binary zeros.

CSA – Global Storage

The SRB must be located in Fixed, Global storage.  When system storage is allocated by GETMAIN the type of stroage is specified by the subpool.  Each system subpool has a set of characteristics associated with it.  We will place our SRB in Common Service Area (CSA) stroage.  There are several subpools that are associated with CSA, each haveing different characteristics.

Subpool Pageable Protect Key Fetch Protect
227 Fixed Requester Key Yes
228 Fixed Requester Key No
231 Pageable Requester Key Yes
239 Fixed Zero Yes
241 Pageable User Key No

For our purposes we will use subpool 228 as it meets our requirements of being fixed (nonpageable) CSA.  Now is proabably a good time to mention that CSA storage is explicitly freed.  Once it is allocated by a GETMAIN request it remains allocated untill a FREEMAIN is issued, or until the next IPL.  If we allocate CSA we should always have a plan to free it.

APF Authorization

Before we can allocate CSA storage we must be authorized.  There are various ways to accomplish this goal.  We can run from an authorized library and set the AC flag at linkedit.  When the program specified on the EXEC statement in JCL is in an APF authorized library and the AC flag is set in the load module a bit will be set in the JSCB indicating the program is APF authorized.  Since I am interested in poking around inside MVS and since I am not too concerned about security on my personal MVS system I have installed a user SVC that will set or clear the APF bit in the JFCB.  By calling the SVC to set the bit it appars to MVS that I am running from an APF authorized library.

Once we have the APF bit set we can use the MODESET macro to get into supervisor state and key zero.  The MODESET macro has two parameters: MODE= and KEY=.  MODE is used to set the PSW to either supervisor state (MODE=SUP) or problem program stat (MODE=PROB).  The KEY parameter can be used to set the PSW protection key to zero (KEY=ZERO) or the protect key associated with the TCB (KEY=NZERO).  It should be noted that once we are in supervisor mode we can also switch PSW keys using the SPKA privledged instruction.

A Simple Program To Schedule A SRB

We now know enough to write a simple program to schedule a SRB.  Our initial SRB routine will not do anything except immediately exit but it will allow us to get through the basics of creating, scheduling and running a SRB routine.

SRB01    CSECT ,
        STM   R14,R12,12(R13)
        LR    R12,R15
        USING SRB01,R12
*
        LA    R1,SAVEA           CHAIN
        ST    R13,4(,R1)              ON
        ST    R1,8(,R13)                SAVE
        LR    R13,R1                        AREA

We begin by saving the caller’s registers, establishing a base register, and setting up a new register save area.

*                                                     
******************************************************
*                     GET INTO SUP STATE, KEY ZERO    
******************************************************
*                                                     
         LA    R1,=C'AUTH'        << GET APF AUTH >>  
         SVC   245                <<     AC = 1   >>  
*                                                     
         MODESET MODE=SUP,KEY=ZERO                    
*                                                     
         LA    R1,0               << RESET APF AUTH >>
         SVC   245                <<      AC = 0    >>

Next I invoke my user SVC to establish APF authorization. On my system I use SVC 245. If you run from an APF authorized library you can remove the SVC 245 calls. If you have a similar SVC installed on your system you may need to modify the code to work.

Next we issue the MODESET macro to set our PSW to supervisor state and protect key zero. Once we are in supervisor state I usually call my SVC 245 to turn off the APF bit in the JSCB. As long as we are in supervisor state or in PSW protect key of 0 through 7 we are considered APF authorized by MVS.

*****************************************************
*                       SET UP CSA STORAGE           
*****************************************************
*                                                    
         LA    R4,WKLEN           LENGTH OF WORK AERA
*                                                    
         GETMAIN R,LV=(R4),SP=228                    
*                                                    
         LR    R6,R1                                 
         USING WKAREA,R6          MAP CSA STORAGE    
*                                                    
         XC    WKAREA(WKLEN),WKAREA

Now that we are in supervisor state and key zero we can allocate our CSA storage. WKLEN is an equated symbol that represents the lenght of our DSECT used to map our CSA storage.  We can then issue a GETMAIN request for subpool 228 to get CSA storage that is globally accessable from all address spaces.  This storage is fixed, non-pageable and will not be fetch protected.  We then save the address of our CSA storage in register 6 and map it with our DSECT.  Finally the storage area is cleared to binary zeros using the exclusive or characters instruction.

WKAREA   DSECT ,                   
SRBAREA  DS    CL(44)              
SRBCODE  DS    CL(ENDSRTN-SRBRTN)  
*                                  
*                                  
WKLEN    EQU   *-WKAREA

Here is our DSECT for our common storage.  First we need 44 bytes to contain the SRB control block.  Next we need a place to copy our SRB routine executable code into CSA.  Since we ultimately plan to schedule a SRB into another address space the code in our private storage area would be unavailable.

*                                                     
         L     R8,CVTPTR          CVT ADDRESS         
         L     R8,0(,R8)          PSATNEW             
         L     R8,12(,R8)         CURRENT ASCB (OURS)

Next we get the address of the ASCB for the address space we are currently located.  First we get the address of the CVT which is always located in low memory at location X’10’ .  I often simply would code  L   R8,16  but here I use the label generated by the CVT mapping macro.  The first word of the CVT points to an area that contains the address of our TCB and our ASCB that is currently dispatched.  We get the ASCB address in register 8 and save it for later.

         LA    R2,SRBCODE         SRB CODE IN CSA      
         LA    R3,ENDSRTN-SRBRTN  LENGTH OF SRB ROUTINE
         LA    R4,SRBRTN          MODEL CODE TO COPY   
         LR    R5,R3                                   
         MVCL  R2,R4              COPY INTO CSA

Now we need to copy our SRB routine into CSA.  Here it set up the registers and use the MVCL instruction to copy the code.  You could also use one or more MVC instructions depending on the length of the code.  The advantage of using MVCL is we don’t have to keep checking the size of the SRB executable routine and add an additional MVC instruction when we exceede a 256 byte boundary.

         LA    R7,SRBAREA         SRB STORAGE AREA
         USING SRB,R7                             
         XC    0(SRBSIZE,R7),0(R7)    CLEAR

Next I clear the SRB control block to binary zeros.  This is not really necessary since I cleared the entire area after the GETMAIN but I include it here so when we later reuse the SRB control block I am reminded to clear it first.

         MVC   SRBID,=CL4'SRB '   SRB ID                      
*                                                             
         ST    R8,SRBASCB         TARGET ASCB TO SCHEDULE TO  
*                                                             
*                                                             
         LA    R1,SRBCODE                    SRB ENTRY POINT  
         ST    R1,SRBEP                                       
*                                                             
         LA    R1,SRBCLEAN-SRBRTN(,R1)       SRB PURGE ROUTINE
         ST    R1,SRBRMTR                                     
*                                                             
         LA    R1,0                          PARM LIST        
         ST    R1,SRBPARM

Now we can fill in the required fileds for the SRB control block.  First we move in the eyeball identifier ‘SRB ‘.  For now we will schedule the SRB into our own address space.  We set the entry point address to the location in CSA where we copied the SRB routine executable code.  We also set the entry point of a purge routnie.  Since our SRB routine will immediately exit we don’t need to pass any parameters for now.  This completes our SRB control block and it is now ready for scheduling.

*************************************************
*                       SCHEDULE SRB AND WAIT    
*************************************************
*                                                
         SCHEDULE SRB=(R7),SCOPE=LOCAL

We can now use the SCHEDULE macro to schedule to add our SRB to the dispatcher queue.  To issue the SCHEDULE macro we must be in key zero and supervisor state.  We must also include the mapping macros for the CVT and SRB data areas.  We must provide the address of our SRB in CSA and we set our priority to LOCAL or address space priority.

*                                                                                                                                       
         STIMER WAIT,DINTVL=WAITTIME         WAIT FOR SRB TO COMPLETE
*

Now we can issue a WAIT macro to pause and give the SRB time to execute.  Since our SRB does not do anything we don’t have any indication of when it is complete.  By waiting 10 seconds (which is a very long time) our SRB should have plenty of time to be dispatched and to complete execution before we clean up.

         DS    0D                                 
WAITTIME DC    C'00001000'        WAIT 10 SECONDS 
*                HHMMSSTH

Our wait time value must be in a double word in unpacked format.

CLEANUP  DS    0H                          
         LA    R4,WKLEN                    
*                                          
         FREEMAIN R,LV=(R4),A=(R6),SP=228  
*                                          
         MODESET MODE=PROB,KEY=NZERO

When we exit from our wait we can cleanup and exit.  First it is important to free the CSA stroage we allocated.  If we fail to free the CSA it will remain allocated until the next IPL.  Failure to free CSA storage can result if running out of CSA and make an IPL necessary.  It is always good practice to make every effort to clean up any system resources we use.  For production quality code we would include some error recovery code to free the CSA in the event our program abnormally terminated.  Since we are testing in a non-production environment it is not a necessity.

As part of our cleanup we also reset the PSW back to problem program state and TCB storage protect key.

EXIT     DS    0H                                   
         SLR   R15,R15            SET RETURN CODE  
         L     R13,4(,R13)        UNCHAIN SAVE AREA 
         L     R14,12(,R13)       RESTORE R14       
         LM    R0,R12,20(R13)     RESTORE REGS 0-12 
         BR    R14                RETURN TO CALLER

Now all that is left is to restore the caller’s registers and exit back to the caller.

Constants and Data Areas

We need to define one constant, our wait time.  We also need to generate any literal constants using LTORG.  We also have one data area, our register save area.

         DS    0D                                  
WAITTIME DC    C'00001000'        WAIT 10 SECONDS  
*                HHMMSSTH                          
*                                                  
*                                                  
         LTORG ,                                   
*                                                  
*                                                  
SAVEA    DS    18F                SAVE AREA

SRB Routine Code

Now all we need is the code for the SRB routine.  For now we can keep it very simple and as soon as our SRB routine is dispatched it will immediately exit.

SRBRTN   DS    0H                                     
         LR    R6,R15             SRB ROUTINE EP      
         USING SRBRTN,R6                              
*                                                     
         LR    R4,R1              SAVE PARM REGISTER  
*                                                     
         LR    R5,R14             SAVE RETURN ADDRESS 
*                                                     
         BR    R5                  DONE - EXIT        
*                                                     
*                                                     
SRBCLEAN DS    0H                  SRB PURGE ROUTINE                      
         BR    R14
*                     
*                     
         LTORG ,      
*                     
*                     
         DROP  R6     
*                     
*                     
ENDSRTN  EQU   *

CSA Storage Area Dsect

Now we need our DSECT that maps our CSA storage.

WKAREA   DSECT ,                   
SRBAREA  DS    CL(44)              
SRBCODE  DS    CL(ENDSRTN-SRBRTN)  
*                                  
*                                  
WKLEN    EQU   *-WKAREA

Finishing Touches

All that is missing to complete our program is a few system data area mapping macros and the register equates.

*                        
         PRINT OFF       
         CVT   DSECT=YES 
         IHASRB  ,       
         IHAPSA  ,       
*                        
*                        
R0       EQU     0 
R1       EQU     1  
R2       EQU     2  
R3       EQU     3  
R4       EQU     4  
R5       EQU     5  
R6       EQU     6  
R7       EQU     7  
R8       EQU     8  
R9       EQU     9  
R10      EQU     10 
R11      EQU     11 
R12      EQU     12 
R13      EQU     13 
R14      EQU     14 
R15      EQU     15 
*                   
         END     ,

Now we can compile and link edit our program. When we run the program it should wait for ten seconds and then exit.

JOB 6757  $HASP373 SRB01    STARTED - INIT 12 - CLASS A - SYS TCS3
JOB 6757  15.42.10   0.00.10   0.00.00  0000   SRB01     MVSSP    
JOB 6757  15.42.10   0.00.10   0.00.00  0000   SRB01     ######## 
JOB 6757  $HASP395 SRB01    ENDED

If we did something wrong it is very possible running this program will crash MVS. If that happens we can simply restart with an IPL and try to fix the problem.

Cross Memory Post

MVS 3.8 does no have any of the modern cross memory services available software or hardware.  In order to communicate between address spaces some system level code must be used.  Shared data can be placed into Common Service Area (CSA) storage which can be accessed by all address spaces.  If address space A wants to send a message to address space B, address space A could copy the message into an area of CSA known by both A and B.  The problem is how address space B knows the data is available.  We could loop looking for changes but that would consume a lot of CPU time and would not be very efficient.  We could look for changes and upon finding none we could wait some time interval before loooking again.  If the delay interval is set too low a large amount of CPU time would still be consumed.  If the interval is set too high the program becomes unresponsive since a delay is built in.

The normal way to synchronize between multiple tasks is to use the WAIT/POST functionality.  A task issues a WAIT supervisor call pointing to an Event Control Block (ECB).  The signaling task issues a POST supervisor call pointing to the same ECB to wake up the waiting task.  This works very well inside a single address space but does not work across address spaces.

MVS does provide a way to POST and ECB in another address space.  Is is a little more complicated than simply using the POST macro.  In addition to the SVC interface to POST, MVS also provides a Branch Entry.  Using Branch Entry is more complicated and requires the caller to be in supervisor mode and key zero.  It does have the advantage of allowing us to post and ECB in an address space other than our own.

Below is a summary of the registers used as input for Branch Entry POST.

R10 - POST Completion Code (to be placed into ECB)
R11 - ECB Address (high order bit of register must be set to X'80')
R12 - Error Return Address
R13 - ASCB Address of address space containing ECB
R14 - Linkage Return Address
R15 - Entry Point (CVT0PT01)

The high order bit of register 11 determines if the request is a cross memory post.  When calling the Branch Entry POST routine for a non-cross memory post we must hold the Local Lock.  For a cross memory post we do not have to hold any locks but we must be aware that the contents all registers except register 9 will be destroyed.

SRB Cross Memory Post

We now have enough to modify our simple SRB routine to post an ECB to signal a waiting task in another address space.  We will begin by expanding our CSA storage map to include a parmameter list to be passed to the SRB routine.

WKAREA   DSECT ,                                            
PARMLIST DS    0F            PARAMETER LIST FOR SRB ROUTINE 
WAITECB  DS    A             ADDRESS OF LOCAL ECB                            
WAITASCB DS    A             ADDRESS OF WAITING ASCB        
*                                                           
SRBAREA  DS    CL(44)                                       
SRBCODE  DS    CL(ENDSRTN-SRBRTN)                           
*                                                           
*                                                           
WKLEN    EQU   *-WKAREA

We will pass two parameters to the SRB routine. The first is the address of the waiting ECB located in the private area and the second is the address of the ASCB for the waiting address space.  When our SRB routine is dispatched the address of the parmaeter list will be contained in register 1.

SRBRTN   DS    0H                                     
         LR    R6,R15             SRB ROUTINE EP      
         USING SRBRTN,R6                              
*                                                     
         LR    R4,R1              SAVE PARM REGISTER  
         USING PARMLIST,R4                            
*                                                     
         LR    R9,R14             SAVE RETURN ADDRESS 
*                                                     
*                                                     
         LA    R10,X'7F'          POST                
         SLL   R10,24                 COMPLETION CODE 
*                                                     
         L     R11,WAITECB        ECB ADDRESS         
         LA    R1,X'80'           SET                 
         SLL   R1,24                 HIGH-ORDER       
         OR    R11,R1                          BIT    
*                                                     
         LA    R12,POSTERR        ERROR ROUTINE       
         L     R13,WAITASCB       ASCB ADDRESS        
*                                                     
         L     R15,CVTPTR         CVT ADDRESS                
         L     R15,CVT0PT01-CVTMAP(,R15)   POST BRANCH-ENTRY 
         BALR  R14,R15                                       
*                                                            
*                                                            
         BR    R9                  DONE - EXIT               
*                                                            
*                                                            
SRBCLEAN DS    0H                  SRB PURGE ROUTINE         
         XC    0(SRBSIZE,R1),0(R1)                           
         BR    R14                                           
*                                                            
*                                                            
POSTERR  DS    0H                  POST ERROR ROUTINE        
         BR    R14                                           
*                                                            
*                                                            
         LTORG ,

The first thing we do is copy the address of the parm list into register 4.  Next we save the return address in register 9 (this is because register 9 is the only register preserved when we call Branch Entry POST).  Next we set our post code into register 10.  It can be anything we want so I chose X’7F000000′ but it really doesn’t matter. Next we load the address of the ECB into register 11 and set the high order bit to X’80’ to indicate a cross memory post.  The address of our Post Error Routine goes into R12 and the address of the ASCB for the task that is waiting goes into R13.  All the remains is to get the address of the Branch Entry Post routine into register 15 and then call it.  Upon return the contents of all registers except R9 will be lost.  Since all we need to do is exit all we need is the return address we saved in R9.  We also added our Post Error Routine which immediately returns to the caller.

That’s it for the SRB routine but we still need some changes in our code that sets up and schedules the SRB.

                                                               
         L     R9,CVTPTR               CVT ADDRESS               
         L     R9,CVTASVT-CVTMAP(,R9)  ASVT ADDRESS              
         L     R9,ASVTENTY-ASVT(,R9)   FIRST ASCB POINTER        
         L     R9,4(,R9)               ASCB FOR ASID=0002 (JES2)

We could continue to schedule the SRB into our own address space and call the cross memory post routine but we really should schedule the SRB routine into a different address space so we really are doing a cross memory post.  I chose to use the JES2 address space since it is always active and I can be pretty confident it will be in ASID x’0002′.  Again it really doesn’t matter for now and any valid address space could be used.  To find the JES2 ASCB we get the Address Space Vector Table address from the CVT.  We then offset to the list of pointers to ASCBs.  The first entry is ASID x’0001′, the second ASID x’002′, and so on.  We take the address of the second ASCB which should be the addres space for JES2.  We save this address in R9.

         ST    R9,SRBASCB         TARGET ASCB TO SCHEDULE TO

Next we need to place the address of the ASCB  for JES2 into the SRB so it will be scheduled there.

                                                               
         LA    R1,PARMLIST                   PARM LIST               
         ST    R1,SRBPARM                                            
*                                                                    
         ST    R8,WAITASCB        SAVE OUR ASCB ADDRESS INTO PARMLIST
*                                                                    
         LA    R1,LOCALECB                                           
         ST    R1,WAITECB

Now we have to set up the parameter list for the SRB routine.  We place the pointer to the parm list into the SRB control block.  The address of the ASCB for our address space goes into the parameter list along with the address of an ecb.

         WAIT  1,ECB=LOCALECB     WAIT FOR SRB TO COMPLETE

Now instead of setting a delay we wait for our ECB to be posted by the SRB routine.

LOCALECB DC    F'0'

Here is the ECB we will wait on (located in our private storage).

         IHAASVT ,

Finally we need to include the mapping macro for the ASVT. With this we are done and our program can be compiled, link edited and we can run it. If everything goes as planned it should run very quickly.

JOB 6755  $HASP373 SRB02    STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6755  15.39.08   0.00.00   0.00.00  0000   SRB02     MVSSP     
JOB 6755  15.39.08   0.00.00   0.00.00  0000   SRB02     ########  
JOB 6755  $HASP395 SRB02    ENDED

SRB Error Recovery

Now that we can schedule a SRB into another address space and use cross memory post to synchronize between the scheduling task and the SRB it is almost time to start writing some more complex code in our SRB routine. Before doing this we should probably consider what happens when our SRB routine encounters an error.

A Simple Test

We can start with a simple experiment to see what happens when our SRB routine fails.  All we need to do is cause an error condition which can easily be done by inserting the line:

         DC    X'0000'

into our SRB routine. It can be placed anywhere before the BALR to the POST routine. I placed it immediately after the LR to save the address of the parameter list.

When our program is compiled, link edited, and run we see nothing happen.  The SRB is scheduled, the task waits on the ECB, the SRB is dispatched and immediately fails with a S0C1 (or program interruption x’01’ to be more specific) and the ECB is never posted.  The scheduling task has no way of knowing the SRB failed and continues to wait.  If the job is not cancelled by an operator command it should eventually fail with a S522 ABEND.

This is probably not the behaviour we want when our SRB routine fails.  It would probably be better if the scheduling task failed when the SRB routine failed. This can be done with just a few more lines of code.  There are two fields in the SRB control block we need to fill in.  SRBPASID is a two byte field where we place the ASID (not the ASCB address) of the task associated with the SRB.  SRBPTCB is a pointer to the TCB associated with the SRB.  When these fields are specified and the SRB routine fails the failure will be propagated back to the TCB.

We already have the address of our ASCB so it is pretty simple to get the ASID value.  It is also pretty simple to get the address of our TCB at the same time we are finding our ASCB address.

          L     R8,CVTPTR          CVT ADDRESS         
          L     R8,0(,R8)          PSATNEW             
          L     R10,4(,R8)         CURRENT TCB ADDRESS  <------ Insert This Line
          L     R8,12(,R8)         CURRENT ASCB (OURS)

Now register 10 will contain the address of our TCB.

         ST    R10,SRBPTCB        PURGE TCB ADDRESS       
         SLR   R1,R1                                      
         ICM   R1,B'0011',ASCBASID-ASCB(R8)  GET OUR ASID 
         STH   R1,SRBPASID        PURGE ASID

By adding the above lines in our SRB setup code we now should be able to detect SRB errors.  Now we assemble, link edit, and run our test program.

JOB 6771  $HASP100 SRB03    ON INTRDR      RUN TEST PGM            
JOB 6771  $HASP373 SRB03    STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6771  IEF450I SRB03 MVSSP - ABEND S0C1 U0000 - TIME=08.33.41   
JOB 6771   8.33.42   0.00.00   0.00.00  S0C1   SRB03     MVSSP     
JOB 6771   8.33.42   0.00.00   0.00.00  S0C1   SRB03     ########  
JOB 6771  $HASP395 SRB03    ENDED

And there we are!  When the SRB routine abnormally terminates our job ABENDs with a SoC1.  This is much better than waiting for the eventual S522 ABEND.

Functional Recovery Routines

Now we can deal with how to recover from an error while running a SRB routine.  We can’t use ESTAE to trap errors since ESTAE doesn’t work when running under a SRB.  Instead we have to use a Functional Recovery Routine (FRR) to trap the error.  If you are familiar with ESTAE then using a FRR should be pretty familiar.  When a FRR has been established and and error occurs, the FRR will be given control and then decide what action to take.

A FRR is established using the SETFRR macro.

         SETFRR A,FRRAD=(R3),WRKREGS=(R7,R8),RELATED=(DELETE)

This will add a FRR, the address of the FRR is contained in register 3, and we supply two work registers to the macro (registers 7 and 8).  The RELATED parameter is provided to allow a method of associating comments directly with the macro.  It must be specified but the value doesn’t matter to the expansion of the macro.  To use this macro we must include the mapping macros IHAFRRS and IHAPSA.

Now when an error occurs during execution of our SRB the FRR will be given control.  On entry to the FRR register 0 contains the address of a 200 byte FRR work area.  Register 1 contains the address of the SDWA.  Unlike an ESTAE routine where there are conditions where a SDWA may not be available, a SDWA is always passed to the FRR.

Here is a simple FRR that will resume execution of our SRB at a recovery point.  This type of recovery is good when we want to try an action that may fail and recover from that failure.

FRREXIT  DS    0H
         USING FRREXIT,R15
*
         L     R7,RETADDR
         SETRP RC=4,RETREGS=YES,RETADDR=(R7)
         BR    R14
*
RETADDR  DC    A(0)

We use the SETRP macro to set recovery options in the SDWA.  A return code of 4 specifys a retry action.  We indicate that the registers should be restored and that the retry address is contained in register 7.  We then return using register 14 to initiate the retry.

Note that the retry address (RETADDR) must be set before establishing the FRR environment.  We can’t specify it using something like A(RETRY) because we relocate the SRB code from our private area into CSA.  Instead we need to use something like this.

        LA    R1,RETRY
        ST    R1,RETADDR

We now have enough to implement a FRR in our SRB routine.  Here is the updated SRB routine.

SRBRTN   DS    0H                                            
         LR    R6,R15             SRB ROUTINE EP             
         USING SRBRTN,R6                                     
*                                                            
         LR    R4,R1              SAVE PARM REGISTER         
         USING PARMLIST,R4                                   
*                                                            
         LR    R9,R14             SAVE RETURN ADDRESS        
*                                                            
         LA    R1,RTRYRTN         ADDRESS OF RETRY POINT     
         ST    R1,RETADDR         SAVE FOR FRR               
*                                                            
         LA    R3,FRREXIT         ADDRESS OF FRR             
         SETFRR A,FRRAD=(R3),WRKREGS=(R7,R8),RELATED=(DELETE)
*                                                            
         LA    R10,X'41'          POST                       
         SLL   R10,24                 COMPLETION CODE        
*                                                            
         DC    X'0000'            SOC1 ABEND                 
*                                                            
         LA    R10,X'7F'          POST                       
         SLL   R10,24                 COMPLETION CODE        
*                                                            
RTRYRTN  DS    0H                                            
         SETFRR D,WRKREGS=(R7,R8),RELATED=(ADD)              
*                                                            
         L     R11,WAITECB        ECB ADDRESS                
         LA    R1,X'80'           SET                        
         SLL   R1,24                 HIGH-ORDER              
         OR    R11,R1                          BIT           
*                                                            
         LA    R12,POSTERR        ERROR ROUTINE              
         L     R13,WAITASCB       ASCB ADDRESS               
*                                                            
         L     R15,CVTPTR         CVT ADDRESS                
         L     R15,CVT0PT01-CVTMAP(,R15)   POST BRANCH-ENTRY 
         BALR  R14,R15                                       
*                                                            
*                                                            
         BR    R9                  DONE - EXIT               
*                                                        
SRBCLEAN DS    0H                  SRB PURGE ROUTINE     
         XC    0(SRBSIZE,R1),0(R1)                       
         BR    R14                                       
*                                                        
*                                                        
POSTERR  DS    0H                  POST ERROR ROUTINE    
         BR    R14                                       
*                                                        
*                                                        
FRREXIT  DS    0H                                        
         USING FRREXIT,R15                               
*                                                        
         L     R7,RETADDR                                
         SETRP RC=4,RETREGS=YES,RETADDR=(R7)             
         BR    R14                                       
*                                                        
RETADDR  DC    A(0)                                      
*                            
         LTORG ,             
*                            
*                            
         DROP  R4,R6         
*                            
*                            
ENDSRTN  EQU   *

Notice we included a SETFRR macro with the D or delete option to remove our FRR environment once we were past the  section of code where we wanted to trap errors.  If we did not delete our FRR and an error occured after our retry point a endless loop could occur.

Checking The Post Code

Now we have two different post codes used by our SRB routine.  A value of x’7F000000′ indicates success and a value of x’41000000′ indicates a failure.  There is nothing magic about these codes and they only have meaning withing our program.  We can update our scheduling program to report on the post code status.

         CLI   LOCALECB,X'7F'     CHECK FOR GOOD COMPLETION CODE 
         BE    SUCCESS                                           
*                                                                
         CLI   LOCALECB,X'41'     CHECK FOR FAIL COMPLETION CODE 
         BE    FAIL                                              
*                                                                
         WTO   '*** UNKNOWN POST CODE ***',ROUTCDE=(1,11)        
         B     CLEANUP                                           
*                                                                
*                                                                
SUCCESS  DS    0H                                                
         WTO   '*** SUCCESS POST CODE ***',ROUTCDE=(1,11)        
         B     CLEANUP                                           
*                                                                
*                                                                
FAIL     DS    0H                                                
         WTO   '*** FAIL POST CODE ***',ROUTCDE=(1,11)           
         B     CLEANUP

Now with these updates in place we can assemble, linkedit and execute our program.

JOB 6775  $HASP100 SRB04    ON INTRDR      RUN TEST PGM              
JOB 6775  $HASP373 SRB04    STARTED - INIT 12 - CLASS A - SYS TCS3   
JOB 6775  *** FAIL POST CODE ***                                     
JOB 6775   7.39.43   0.00.00   0.00.00  0000   SRB04     MVSSP       
JOB 6775   7.39.43   0.00.00   0.00.00  0000   SRB04     ########    
JOB 6775  $HASP395 SRB04    ENDED

We can remove our abend by commenting out the line

*------->DC    X'0000'            SOC1 ABEND

and then we assemble, linkedit and execute.

6778  $HASP100 SRB04    ON INTRDR      RUN TEST PGM            
6778  $HASP373 SRB04    STARTED - INIT 12 - CLASS A - SYS TCS3 
6778  *** SUCCESS POST CODE ***                                
6778   8.43.04   0.00.00   0.00.00  0000   SRB04     MVSSP     
6778   8.43.04   0.00.00   0.00.00  0000   SRB04     ########  
6778  $HASP395 SRB04    ENDED

An this proves we can capture and report on an error contition in our SRB routine.

Cross Memory Access Using A SRB

Now we know enough to modify our SRB routine to allow us to actually access data in another address space. We just need to make a few simple modifications to our existing code. For our initial test we will retrieve the Job Step program name contained in the JSCB. We can locate the JSCB by following a chain of control blocks beginning with the ASCB. The ASCB resides in common storage it can be accessed from any address space. The ASCB points to the ASXB which resides in private storage. The ASXB has a pointer to a TCB and the TCB points to the JSCB. The JSCB contains the program name we are looking for. We will add code to our SRB routine to follow the control block chain to locate the JSCB and then copy the program name into common storage before posting the ECB.

WKAREA   DSECT ,                                           
PARMLIST DS    0F            PARAMETER LIST FOR SRB ROUTINE
WAITECB  DS    A             ADDRESS OF LOCAL ECB          
WAITASCB DS    A             ADDRESS OF WAITING ASCB       
XMASCB   DS    A             CROSS MEM - ASCB ADDRESS      
XMPGM    DS    CL8           PROGRAM NAME RETURN AREA      
*                                                          
SRBAREA  DS    CL(44)                                      
SRBCODE  DS    CL(ENDSRTN-SRBRTN)                          
*                                                          
*                                                          
WKLEN    EQU   *-WKAREA

We begin by adding two additional fields to our SRB parameters in our CSA storage. First we pass the address of the ASCB of the address space we dispatched our SRB into (XMASCB). We also provide an area to return the program name (XMPGM).

         ST    R9,XMASCB          SAVE TARGET ASCB ADDRESS IN PARMS

We need to place the target ASCB address into the parameter list prior to scheduling the SRB. We already have the ASCB address so we just need to add one line of code.

         LA    R3,FRREXIT         ADDRESS OF FRR              
         SETFRR A,FRRAD=(R3),WRKREGS=(R7,R8),RELATED=(DELETE) 
*                                                             
         LA    R10,X'41'          POST                        
         SLL   R10,24                 COMPLETION CODE         
*                                                             
         L     R1,XMASCB          GET XM ASCB ADDRESS         
         L     R1,ASCBASXB-ASCB(,R1)   GET ASXB ADDRESS       
         L     R1,ASXBLTCB-ASXB(,R1)   GET TCB ADDRESS        
         L     R1,TCBJSCB-TCB(,R1)     GET JSCB ADDRESS       
         LA    R1,JSCBPGMN-IEZJSCB(,R1)  POINT TO PGM NAME    
         MVC   XMPGM,0(R1)                                    
*                                                             
         LA    R10,X'7F'          POST                        
         SLL   R10,24                 COMPLETION CODE         
*                                                             
RTRYRTN  DS    0H                                             
         SETFRR D,WRKREGS=(R7,R8),RELATED=(ADD)

We insert our new SRB code in the FRR protected section. This way if an error occurs (like a SOC4), the error will be trapped and reported back to the caller with a post code. The fail post code is initially placed into register 10. It will be updated if the program name is successfully copied. Next we get the pointer to the ASCB. From there we chain down to the JSCB and point to the program name field. We can then copy the program name into our parameter area in CSA. Once the name is successfully copied we can update the post code to indicate success and then continue on to the cross memory post.

SUCCESS  DS    0H                                         
         WTO   '*** SUCCESS POST CODE ***',ROUTCDE=(1,11) 
*                                                         
         MVC   WTOMSG+12(8),XMPGM                         
WTOMSG   WTO   '>>> ******** <<<',ROUTCDE=(1,11)          
         B     CLEANUP

If the ECB is posted with the success code we can copy the program name from the CSA area into our private storage.  In this case we copy it into a WTO message.  This will cause the program name to be displayed on the operator console.

          IHAASXB ,                 
          IKJTCB  DSECT=YES,LIST=NO 
          IEZJSCB ,

We need to add the mapping macros for the ASXB, TCB, and JSCB.

JOB 6806  $HASP100 SRB05    ON INTRDR      RUN TEST PGM            
JOB 6806  $HASP373 SRB05    STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6806  *** SUCCESS POST CODE ***                                
JOB 6806  >>> HASJES20 <<<                                         
JOB 6806  20.46.41   0.00.00   0.00.00  0000   SRB05     MVSSP     
JOB 6806  20.46.41   0.00.00   0.00.00  0000   SRB05     ########  
JOB 6806  $HASP395 SRB05    ENDED

Now we assemble, link edit, and run our program.  Everything looks good – since we scheduled our SRB into the address space for JES2 we should expect to find HASJES20 as the job step program.  We have successfully accessed storage in the private area of another address space.

SVC Routines – Introduction

We can now explore how to add system level functionality using SVC (Supervisor Call) routines.  SVC routines are invoked through the use of the SVC machine instruction.  A SVC instruction causes a SVC Interruption to occur.  It effectively allows for a special type of call instruction that can switch between problem mode execution and supervisor mode.  SVC routines are defined at SYSGEN time.  SVC routines are categorized into six types.  Type 1, 2, and 6 SVC routines are linked as part of the resident control program.  Type 3 and 4 SVC routines reside in the Link Pack Area (LPA) and may be either fixed or pageable.  All SVC routines must be reentrant.  I will focus on type 3/4 SVC routines since they reside in LPA as individual modules and are less restrictive – and they provide all the functionality I am looking for.

SVC modules must have a specific name in the format:

Type 1, 2,  6 IGCnnn nnn = Signed Decimal Number
Type 3 IGC00nnn
Type 4 IGCssnnn ss = load module number -1

There are a maximum of 256 SVC routines that can be defined (0-255).  The nnn part of the name indicates the SVC number.  It is a signed decimal number so the last digit contains the sign in the high order four bits (x’C0′)  make the last digit a letter (A-I) for the numbers zero through nine.  If the last digit is zero then the last character is X’C0′ or ‘{‘.  For example a Type 3 SVC with the number 123 would be named “IGC0012C”.  If it was SVC 130 it would be named “IGC0013{“.  Once you understand the way the names are generated it is easy to deal with.  The difference between Type 3 and 4 SVC routines is that Type 3 routines consist of a singe module and type 4 routines are made up multiple modules.  For our purposes Type 3 and 4 SVC routines are the same.  A Type 5 SVC is a placeholder and indicates the SVC will be added after the SYSGEN in complete.

Since the SVC call is routed through the SVC interrupt handler the SVC routine does not have to save the callers registers (they are saved by the system in the Request Block).  Registers 0, 1, 13, and 15 are passed from the caller to the SVC routine.  On return the system restores registers 2 through 12.  The SVC routine may pass information back to the caller in registers 0, 1, and 15.  Register 13 usually points to a save area established by the calling routine.  It may be necessary for the SVC routine to establish a save area if standard call linkage will be used to call other routines.  Registers 3 through 7 contain parameters passed by the SVC interrupt handler.  Here is a summary of register contents on entry to a SVC routine:

 0  Same as when SVC was issued
 1  Same as when SVC was issued
 2  Unpredictable
 3  A(CVT)
 4  A(TCB)
 5  A(SVRB) Type 2,3,4
 6  Entry Point of SVC Routine
 7  A(ASCB)
 8  Unpredictable
 9  Unpredictable
10  Unpredictable
11  Unpredictable
12  Unpredictable
13  Same as when SVC was issued
14  Return Address
15  Same as when SVC was issued

A Simple SVC Routine

Now we can write a simple SVC routine.  We will accept two input parameters in registers 0 and 1.  The SVC routine will add the contents of these two registers and return the result in register 15.  This is really a very silly SVC routine but it will prove that we understand the basics of writing our own SVC.

On my system I happen to know that SVC number 230 is a Type 3 SVC and it is currently not in use.  I will use it for my test SVC routine but you may have to use another SVC number depending how SVC routines are defined and used on your system.

SVC01    CSECT ,        
         USING SVC01,R6 
*                       
         LR    R15,R0   
         AR    R15,R1   
*                       
         BR    R14

Here is our whole SVC routine (minus the equates for the registers).  Our load module must be named to reflect the SVC number (“IGC0023A” for SVC 231) but the internal CSECT name can be anything we want.  We establish addressability using register 6 as our base register since it already contains the entry point address.  We copy the value of register 0 into register 15 and then add teh value of register 1.  All that is left is to return using the address in register 14.  The contents of registers 0, 1, and 15 will be returned to the caller.

Now we can assemble and link into SYS1.LPALIB.

Next we need a test program to invoke our new SVC.  Here is the main part of the test program:

         LA    R0,111                     
         LA    R1,222                     
         SVC   231                        
*                                         
         CVD   R15,DOUBLE                 
         MVC   RESULT,=X'4020202020202120'
         ED    RESULT,DOUBLE+4            
*                                         
         MVC   WTO+8(8),RESULT            
WTO      WTO   '++++++++',ROUTCDE=(1,11)

I left out the program linkage but once our program is up and running we load up our two input parameter registers and issue the SVC instruction to call our SVC routine.  On return from the SVC we convert the return value in register 15 to decimal and use the edit instruction to make it printable.  The result is moved into the WTO parameter list and a message is sent to the console.

JOB 6815  $HASP373 SVC01T   STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6815  IEF450I SVC01T MVSSP - ABEND SFE7 U0000 - TIME=07.06.47  
JOB 6815   7.06.48   0.00.00   0.00.00  SFE7   SVC01T    MVSSP     
JOB 6815   7.06.48   0.00.00   0.00.00  SFE7   SVC01T    ########  
JOB 6815  $HASP395 SVC01T   ENDED

When we try running our test program we get a System ABEND FE7.  Notice that X’E7′ is 231 decimal which is our SVC number.  This ABEND indicates the SVC has not been installed.  To actually get our SVC routine installed we need to IPL and CLPA (Create Link Pack Area) or we could use MLPA (Modify Link Pack Area) to do a temporary install of our routine.  A normal IPL does not change the LPA.  It is only rebuilt when CLPA is specified.

Now after a quick IPL with a CLPA we run our test again:

JOB 6825  $HASP373 SVC01T   STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6825  +     333                                                
JOB 6825   7.31.17   0.00.00   0.00.00  0000   SVC01T    MVSSP     
JOB 6825   7.31.17   0.00.00   0.00.00  0000   SVC01T    ########  
JOB 6825  $HASP395 SVC01T   ENDED

And we get the expected result (111+222=333) which proves we have successfully written, installed, and invoked a SVC routine.

SVC Screening

SVC screening provides a way of screening (or intercepting) SVC calls at the task level.  A SVC screen table is created and the address is placed in a TCB.  Any SVC calls from that task that are marked for screening will be intercepted.  Control is passed to the screen routine from the SVC interrupt handler in exactly the same way SVC routines are invoked.

There are several implications of SVC screening.  First we can easily test new SVC code without the need to IPL and perfrom a CLPA or MLPA.  Also the SVC code is only active for tasks were the screening is activated.  With SVC screening we can test a new SVC routine or replace an existing SVC routine.  This applies to both user and system SVC routines.  It also provides a method to front-end SVC calls.

There are two fields in the TCB related to SVC screening.  TCBSVCS is a bit in the TCBFLGS7 field that indicates SVC screening is active if set to one or inactive if set to zero.  TCBSVCA2 is the pointer to the SVC screen table.  The screen table is 264 bytes long.  The first four bytes are the address of the SVC intercept routine that receives control when a screened SVC is invoked by the task.  The next four bytes  are flags that indicate the attributes of the SVC routine.  The first flag byte indicates the SVC type (X’00’ – Type 1, X’80’ – Type 1, X’C0′ – Type 3/4)  The second flag byte is not used and should be binary zeros.  The third and fourth flag bytes indicate the locks to be obtained before passing control to the SVC routine.  Binary zeros indicate no locks are to be obtained.  The next 256 bytes indicate which SVC numbers should be intercepted.  Each byte is a flag for a SVC number.  If the byte is set to X’80’ then the SVC is not to be intercepted.  If they byte is set to X’00’ then the SVC should be intercepted.   The SVC type and locks flags apply to all intercepted SVC numbers.

We now have enough information to write some code to test SVC screening.

SVC02    CSECT ,                                         
         SAVE  (14,12),,SVC02     SAVE CALLERS REGISTERS 
*                                                        
         LR    R12,R15            ESTABLISH              
         USING SVC02,R12                   BASE REGISTER 
*                                                        
         LA    R1,SAVEA           CHAIN                  
         ST    R1,8(,R13)              NEW               
         ST    R13,4(,R1)                 SAVE           
         LR    R13,R1                         AREA       
*

We start with our standard program linkage.

         LA    R1,=C'AUTH'        GET APF AUTHORIZATION    
         SVC   245                                         
*                                                          
         MODESET MODE=SUP         GET INTO SUPERVISOR MODE 
*                                                          
         LA    R1,0               RESET APF AUTHORIZATION  
         SVC   245

Next we obtain APF authorization using the SVC I have installed on my system for testing. You could also run from an APF authorized library. Once APF authorized the MODESET macro is used to swap into supervisor mode and then I clear the APF authorization. This is not really necessary and it shouldnt be necessary to reset it.

         IPK   ,                  GET PSW PROTECT KEY 
         LR    R11,R2             SAVE PK IN R11      
*                                                     
         SPKA  0                  GET INTO KEY ZERO

Next I save the current protect key from the PSW using the IPK instruction. The protect key is placed into register 2 so I copy it to register 11 to save it. I then use the SPKA instruction to get into protect key zero.

         GETMAIN R,LV=264,SP=253

Now we getmain some stroage for our SVC screen table. I use subpool 253 which is Fixed LSQA. This storage is task related and will automaticaly be freed when the task terminates. The storage is not fetch protected and is in key zero.

         LR    R3,R1              SAVE STORAGE ADDRESS         
         XC    0(8,R3),0(R3)      CLEAR FIRST 8 BYTES          
         LA    R1,SVCINT          ADDRESS OF SVC INTERCEPT RTN 
         ST    R1,0(,R3)          SAVE INTO PARMAMETER BLOCK   
         MVI   4(R3),X'C0'        INDICATE TYPE 3/4 SVC

The address of the LSQA storage is copied into register 3 and the first 8 bytes are zeroed out. The address of the routine to receive control from the SVC interrupt handler is placed in the first four bytes. The first flag byte is set to X’C0′ to indicate a Type 3/4 SVC. The lock flags are zero indicating no locks should be obtained.

         LA    R2,8(,R3)          POINT TO 256 BYTE SVC LIST    
         LA    R1,256                                           
INITLOOP DS    0H                                               
         MVI   0(R2),X'80'        INITIALIZE TO DO NOT INTERCEPT
         LA    R2,1(,R2)          NEXT BYTE                     
         BCT   R1,INITLOOP        LOOP BACK

Now we initialize the 256 byte list. Each byte in the list represents one SVC number. The first byte is for SVC 0, the next for SVC 1 and so on. We set each to a value of X’80’ so the SVC is not intercepted.

 *                                                           
          LA    R2,8(,R3)          POINT TO 256 BYTE SVC LIST
          MVI   230(R2),X'00'      INTERCEPT SVC 230         
 *

Now we indicate which SVC requests should be intercepted by setting the corresponding byte to X’00’. I chose to use SVC 230 because it is currently unused on my system. I does not matter how the SVC is defined in the SYSGEN since it is ignored for SVC screening.  Caution should be used to not accidently intercept a SVC that is currently in use on your system.

*                                                                    
         L     R2,16              CVT                                
         L     R2,0(,R2)          OLD/NEW POINTER                    
         L     R2,4(,R2)          TCB ADDRESS                        
         USING TCB,R2                                                
*                                                                    
         ST    R3,TCBSVCA2        STORE SCREEN TABLE ADDRESS INTO TCB
         OI    TCBFLGS7,TCBSVCS   TURN ON SVC SCREENING

Now we locate the address of our current TCB and store the address of the screen table into the TCBSVCA2 field.  Next we set the TCBSVCS bit to activate screening.

         SPKA  0(R11)             RESTORE PROTECT KEY                
*                                                                    
         SVC   230                SHOULD BE CAPTURED BY SVC SCREENING

Now we can restore our PSW protect key.  It is always a good idea to only operate in key zero only when necessary.  Now we issue SVC 230 to test our SVC screening intercept.

         L     R13,4(,R13)        UNCHAIN SAVE AREA         
         LM    R14,R12,12(R13)    RESTORE CALLERS REGISTERS 
         SLR   R15,R15            ZERO RC                   
         BR    R14                RETURN TO CALLER

Now we can exit back to the caller.

SVCINT   DS    0H                                            
         USING SVCINT,R6          SET BASE REGISTER          
*                                                            
         LR    R11,R14            SAVE RETURN ADDRESS        
*                                                            
         WTO   'HELLO FROM SVC SCREEN ROUTINE',ROUTCDE=(1,11)
*                                                            
         LR    R14,R11            RESTORE RETURN ADDRESS     
         BR    R14                EXIT SVC ROUTINE

Here is our SVC intercept routine.  The register contents are standard for a SVC routine.  We use register 6 as our base register.  The return address is saved in register 11.  All our SVC routine does is issue a WTO to write a message to the console.  Since we defined our SVC intercept as a Type 3/4 our SVC routine can issue SVC calls.  We then exit back to our caller.

SAVEA    DS    18F                REGISTER SAVE AREA
*                                                   
         LTORG ,                                    
*                                                   
         PRINT NOGEN                                
         IKJTCB DSECT=YES,LIST=NO                   
*                  
R0       EQU   0   
R1       EQU   1   
R2       EQU   2   
R3       EQU   3   
R4       EQU   4   
R5       EQU   5   
R6       EQU   6   
R7       EQU   7   
R8       EQU   8   
R9       EQU   9   
R10      EQU   10  
R11      EQU   11  
R12      EQU   12  
R13      EQU   13  
R14      EQU   14  
R15      EQU   15  
*                  
         END    ,

We finish up with our data areas and register equates.

JOB 6828  $HASP373 SVC02    STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6828  HELLO FROM SVC SCREEN ROUTINE                            
JOB 6828   9.21.07   0.00.00   0.00.00  0000   SVC02     MVSSP     
JOB 6828   9.21.07   0.00.00   0.00.00  0000   SVC02     ########  
JOB 6828  $HASP395 SVC02    ENDED

Now we can assemble, link edit, and execute and we get our message. We have successfully intercepted SVC 230.

*        OI    TCBFLGS7,TCBSVCS   TURN ON SVC SCREENING

Just to prove that we are really intercepting a SVC call I commented out the line that sets the TCBSVCS bit so that SVC screening is not active.  Upon assembling, link editing, and executing we get:

JOB 6831  $HASP100 SVC02    ON INTRDR      RUN TEST PGM           
JOB 6831  $HASP373 SVC02    STARTED - INIT 12 - CLASS A - SYS TCS3
JOB 6831  IEF450I SVC02 MVSSP - ABEND SFE6 U0000 - TIME=08.23.57  
JOB 6831   8.23.57   0.00.00   0.00.00  SFE6   SVC02     MVSSP    
JOB 6831   8.23.57   0.00.00   0.00.00  SFE6   SVC02     ######## 
JOB 6831  $HASP395 SVC02    ENDED

A System ABEND FE6 indicates that SVC X’F6′ (230 decimal) was called but the SVC routine is not installed.

Screening Multiple SVC Calls

We have successfully managed to use SVC screening to intercept a SVC call.  The only problem is we can only specify one routine to receive control for the intercepted SVC(s).  What if we want to intercept more than one and execute specific code for each unique SVC call?  We have to add some logic to determine what SVC number was called.  Fortunately this information is saved in a Request Block.  When our SVC intercept routine is entered register 5 contains the address of the Supervisor Request Block (SVRB) that was created by the SVC interrupt handler.  This SVRB does not contain information about the SVC call but does point to the previous RB that does contain the system status that was saved when the SVC instruction caused an interrupt. By examining the previous RB we can determine the SVC number assoicated with the call to our intercept routine.

         USING RBBASIC,R5         MAP THE SVRB                     
*                                                                  
         L     R9,RBLINK          LINK TO PREVIOUS RB              
         LA    R9,0(,R9)          CLEAN UP ADDRESS                 
         BCTR  R9,0               BACK UP TO LAST BYTE OF RB PREFIX

Since register 5 contains the address of the SVRB we can use it to find the previous RB.  First we map it against the RBBASIC section of the Request Block.  We use the RBLINK field to get the address of the previous RB.  I use the LA instruction to “clean up” the address, that is to clear the high order bits of the address.  We then subtract one from that address so register 9 will point to the last byte of the prefix section of the RB that is located right before the beginning of the RBBASIC section.  The last byte of the RB prefix contains the SVC interruption code or SVC number.

          CLI   0(R9),230                                       
          BE    SVC230                                          
 *                                                              
          CLI   0(R9),231                                       
          BE    SVC231                                          
 *                                                              
          WTO   '*** NOT SVC 230 OR SVC 231 ***',ROUTCDE=(1,11)

Now we can simply use a CLI instruction to check the SVC number and branch to the appropriate processing routine. We should have some type of error code in place in the event the SVC number fails to match (because we made some type of coding error). Here we simply issue a WTO and then exit.

SVC230   DS    0H                                        
         WTO   '++++++++ SVC 230 ++++++++',ROUTCDE=(1,11)
*                                                        
         LR    R14,R11            RESTORE RETURN ADDRESS 
         BR    R14                EXIT SVC ROUTINE       
*                                                        
SVC231   DS    0H                                        
         WTO   '++++++++ SVC 231 ++++++++',ROUTCDE=(1,11)
*                                                        
         LR    R14,R11            RESTORE RETURN ADDRESS 
         BR    R14                EXIT SVC ROUTINE

Our SVC routines aren’t much more interesting but they will reveal which SVC number was called.

         SVC   230                SHOULD BE CAPTURED BY SVC SCREENING 
         SVC   231                SHOULD BE CAPTURED BY SVC SCREENING 
         SVC   231                SHOULD BE CAPTURED BY SVC SCREENING 
         SVC   230                SHOULD BE CAPTURED BY SVC SCREENING

Now we can issue some SVC calls and see what happens.

JOB 6840  $HASP373 SVC03    STARTED - INIT 12 - CLASS A - SYS TCS3
JOB 6840  ++++++++ SVC 230 ++++++++                               
JOB 6840  ++++++++ SVC 231 ++++++++                               
JOB 6840  ++++++++ SVC 231 ++++++++                               
JOB 6840  ++++++++ SVC 230 ++++++++                               
JOB 6840   8.55.05   0.00.00   0.00.00  0000   SVC03     MVSSP    
JOB 6840   8.55.05   0.00.00   0.00.00  0000   SVC03     ######## 
JOB 6840  $HASP395 SVC03    ENDED

And when we execute the results are just we would have expected.

Intercepting FIND/BLDL

Now that we know how to intercept SVC calls we can try something more interesting.  When a program is assembled the various macro contained in the source code have to be read from the macro library.  As the assembler reads these macros they are located using SVC 18 (FIND/BLDL).  By intercepting SVC 18 we can list the macros as they are being accessed by the assembler.

First we need to look at the input registers to SVC 18.  Register zero points to a parameter list and register one contains a DCB address or zero.  If the request is for BLDL then the contents register one will be positive.  If the request is for find then contents of register one will be negative.  For this excercise we only care about FIND and not BLDL so we can ignore the parameter list for BLDL.  For a FIND request register zero points to an eight-byte member name.

Now all we have to do is intercept calls to SVC 18 and print out the member name each time we encounter a FIND request.  In order for the assembler to work we will have to reissue the SVC call so the real SVC 18 can locate the member in the PDS.

         MVI   18(R2),X'00'       INTERCEPT SVC 18  BLDL/FIND

First we include SVC 18 in our list of intercepted SVC calls in the screen table.  By setting the corresponding byte in the screen table to X’00’ instead of X’80’ we will cause SVC 18 to be intercepted.

         CLI   0(R9),18           BLDL/FIND
         BE    SVC18

In our SVC processing routine we need to check for SVC number 18 as the interrupt code in the RB.

SVC18    DS    0H                          
         LR    R8,R0              SAVE R0  
         LR    R9,R1              SAVE R1  
         LR    R10,R15            SAVE R15

To process our SVC 18 interrupt we first save the parameter registers passed to the SVC routine.

          LTR   R1,R1                                 
          BP    SKIP18                  BRANCH IF BLDL

Now we check to see if the request is for BLDL or for FIND.  For now we will ignore BLDL requests.

         ST    R0,FWORD           SAVE R0 CONTENTS          
         UNPK  WORK(9),FWORD(5)   UNPACK                    
         TR    WORK(8),HEXTAB-C'0'                          
         MVC   WTO18+18(8),WORK                             
*                                                           
         ST    R1,FWORD                                     
         UNPK  WORK(9),FWORD(5)                             
         TR    WORK(8),HEXTAB-C'0'                          
         MVC   WTO18+30(8),WORK                             
*                                                           
         MVC   WTO18+39(8),0(R8)       COPY FIND MEMBER NAME
*                                                           
*               8.10...15...20...25...30...35...40...45...50
WTO18    WTO   'SVC 18 R0=******** R1=******** ********',   
               ROUTCDE=(1,11)

If it is a FIND request we make the contents of registers zero and one printable.  We do this by first storing the contents of the register into a full word.  Next we unpack the full word and finally we have to translate it to make it printable.  The result is copied into the message area of a WTO along with the member name which is pointed to by register zero (which was copied into register 8 for save keeping).  One think to note here is that we are not writing reentrant code.  This is not the way a SVC routine should be written but for now we can get away with it.

SKIP18   DS    0H                                             
         LR    R0,R8                                          
         LR    R1,R9                                          
         LR    R15,R10                                        
         NI    TCBFLGS7,255-(TCBSVCS)  TURN OFF SVC SCREENING 
         SVC   18                                             
         OI    TCBFLGS7,TCBSVCS        TURN ON SVC SCREENING  
         LR    R14,R11            RESTORE RETURN ADDRESS      
         BR    R14                RETURN TO CALLER

Finally we reissue the SVC call.  First we restore the parameter registers.  In order to allow the SVC call to actually go through instead of being intercepted again, and causing an endless loop, we have to temporarly disable screening by clearing the TCBSVCS bit.  Once we issue the SVC we can once again set the bit to resume screening.  All that remins is to do is to restore the return address and return to the caller.

        MODESET MODE=PROB        GIVE UP SUPERVISOR STATE

In our previous test of SVC screening we reset the APF Authorization bit in the JSCB using my User SVC 245 after getting into supervisor state using MODESET.  Before transfering control to the assembler we need to issue MODESET to restore us to problem state.

         LR    R1,R9              RESTORE PARM REG             
         LINK  EP=IFOX00          TRANSFER CONTROL TO ASSEMBLER

Before calling the assember we need to restore the parameter register contents which was saved off in register nine.

JOB 6911  $HASP373 RUNSVX   STARTED - INIT 12 - CLASS A - SYS TCS3
JOB 6911   6.02.51   0.00.00   0.00.00  0000   RUNSVX    COMPRESS 
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IHARB                    
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IKJRB                    
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IEZXRB                   
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IEZBITS                  
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IKJTCB                   
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 TESTAUTH                 
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IHBERMAC                 
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 WTO                      
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IHBINNRA                 
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 DETACH                   
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 WAIT                     
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 ATTACH                   
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 IHBOPLST                 
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 GETMAIN                  
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 MODESET                  
JOB 6911  SVC 18 R0=00096C68 R1=FFF69718 SAVE                     
JOB 6911   6.02.51   0.00.00   0.00.00  0000   RUNSVX    ASM     
JOB 6911   6.02.51   0.00.00   0.00.00  0000   RUNSVX    ########
JOB 6911  $HASP395 RUNSVX   ENDED

After assembling and link editing I modified my assembler JCL and replaced the assembler program name (EXEC PGM=IFOX00) with my SVC screening program (EXEC PGM=SVCX) and added a STEPLIB.  Here are the results of running it.  We get a list of all the macros, including the inner macros, that were used in the assembly.

SVC Screening Propagation

We now have SVC screening working but only for one task (TCB).  If we attach a subtask the SVC screening fields are not propagated to the new task.  In later versions of MVS there is an option to set an additional flag in the TCB that will cause ATTACH processing to copy the SVC screening related fields.  We could modify the ATTACH SVC routine to propagate these fields, in fact it would be pretty simple.  Instead we will take a more interesting, and complex way to solve this problem.  We will use SVC screening to intercept ATTACH SVC calls and propagate the SVC screening fields in our intercept routine.

         MVI   42(R2),X'00'       INTERCEPT SVC 42  ATTACH

First we set the corresponding byte in our screen table for SVC 42 (ATTACH).

         CLI   0(R9),42           ATTACH 
         BE    SVC42

In our intercept routine we check for SVC 42 and branch to process it.

SVC42    DS    0H                                       
         LR    R14,R11            RESTORE RETURN ADDRESS
         L     R6,=V(SVX42)       SVC 42 ROUTINE        
         BR    R6                 TRANSFER CONTROL

First we restore the return address to register 14 and then we load the address of our SVC 42 processing routine into register 6 and branch to it. Entry to our routine will be exactly like a SVC call entry.

SVX42    CSECT ,                                         
         USING SVX42,R6           ESTABLISH BASE REGISTER
         USING TCB,R4             MAP TCB                
         USING RBSECT,R5          MAP RB

We start by establishing a base register and mapping the TCB and RB control blocks.

         LR    R8,R14             SAVE RETURN ADDRESS  
         LR    R9,R1              SAVE PARM LIST       
         LR    R10,R15            SAVE ATTACH PARM LIST

Next we save the return address contained in register 14, the parameter list for the attached program contained in register 1, and the parameter list for the ATTACH SVC contained in register 15.

         MODESET EXTKEY=RBT234,WORKREG=2  GET CALLERS PROT KEY

Now we need to get into the storage protect key of the issuer or the SVC. For this we use the MODESET macro and specify EXTKEY=RBT234 indicating the SVC is a type 2, 3, or 4. We also specify register 2 is to be used as a work register.

         GETMAIN R,LV=ATLSTSIZ+4,SP=229              
*                                                    
         LR    R7,R1              POINT TO WORK AREA 
         USING ATTCHLST,R7

Now we getmain some storage to make a copy of the ATTACH parameter list. This is necessary because we will copy the parameter list and modify it before reissuing the SVC. We add four additional bytes to be used by our intercept routine. The allocated storage will be in the same key as the issuer of the SVC. The copy of the parameter area is pointed to by register 7.

         MVI   ATTCHLST+ATLSTSIZ,X'00'   RESET AUTH SWITCH     
*                                                              
         TESTAUTH FCTN=1,STATE=YES,KEY=YES,RBLEVEL=2           
*                                                              
         LTR   R15,R15             IS CALLER AUTHORIZED        
         BNZ   AUTH010             NO - BRANCH                 
*                                                              
         OI    ATTCHLST+ATLSTSIZ,X'80'   SHOW CALLER AUTHORIZED
AUTH010  DS    0H

We will need to know if the issuer of the SVC is APF authorized or not. First we set our flag byte, past the end of the parameter list, to zero indicating the caller is not authorized. Next we use the TESTAUTH macro to determine if the caller was APF authorized. We have the TESTAUTH routine check the JSCB APF authorization bit as well as checking for supervisor state and PSW protect key less than eight. If any of these conditions are true the caller is considered authorized and we set our flag bit.

         MVC   0(ATLSTSIZ,R7),0(R10)    COPY CALLERS PARM LIST

Now we make a copy of the ATTACH parameter list.

        
         TM    ATTCHLST+ATLSTSIZ,X'80'  IS CALLER AUTHORIZED           
         BO    AUTH020                  YES - BRANCH                   
***********************************************************************
*                  RESET ALL AUTHORIZED PARAMETERS                     
***********************************************************************
         NI    ATINDS,255-(ATJSTCB+ATMODE+ATSVAREA+ATKEY+ATDISP+ATJSCB)
         NI    ATFLAGS1,255-ATRSAPF                                    
         XC    ATJSCBA,ATJSCBA                                         
         XC    ATTNSHLV,ATTNSHLV                                       
         XC    ATTID,ATTID                                             
         B     AUTH030             ATDISP ONLY VALID IF APF AUTH       
*                                                                      
*                                                                      
AUTHO20  DS    0H                                                      
         TM    ATINDS,ATDISP       WAS NO DISP SPECIFIED               
         BNO   AUTH030             NO - BRANCH                         
*                                                                      
         OI    ATTCHLST+ATLSTSIZ,X'40'   REMEMBER NO DISP              
AUTH030  DS    0H

If the caller is not APF authorized we clear all of the flags that are only valid for authorized callers and are ignored otherwise. If the caller is authorized we check to see if the ATDISP flag was set indicating the TCB should not be automatically made dispatchable. This is done because we will force this bit before reissuing ATTACH.

         OI    ATINDS,ATDISP      FORCE NO DISPATCH

Now we set the ATDISP flag in our copy of the ATTACH parameter list. Setting this flag bit will make the TCB initially marked non-dispatchable. This is necessary to allow us to set the SVC screening fields in the new TCB before be begins execution.

         SPKA 0                   GET INTO KEY ZERO            
         NI   TCBFLGS7,255-TCBSVCS  TURN OFF SVC SCREENING     
         MODESET EXTKEY=RBT234,WORKREG=2   BACK TO CALLERS KEY 
*                                                              
         LR   R15,R7              OUR UPDATED ATTACH PARM LIST 
         LR   R1,R9               CALLERS R1                   
         SVC  42                  ATTACH                       
         LR   R11,R1              SAVE NEW TCB ADDRESS         
         LR   R12,R15             SAVE RC

Now we get ready to reissue the ATTACH SVC. First we get back into protect key zero. Next we turn off SVC screening for the current TCB so we will not reintercept the call. We then get back into the caller’s protect key using MODESET. We restore the parameter registers 1 and 15 before call SVC 42. We then save the return parameter register values so they can be returned to our caller later.

         SPKA  0                  BACK TO KEY ZERO                 
         OI    TCBFLGS7,TCBSVCS   TURN SVC SCREENING BACK ON       
         LR    R1,R11             RESTORE PARM                     
         LTR   R15,R12            CHECK RC                         
         BNZ   FREEEXIT           EXIT IF NOT ZERO                 
*                                                                  
         L     R1,TCBSVCA2        GET SCREEN TABLE ADDRESS         
         DROP  R4                                                  
         USING TCB,R11            MAP NEW TCB                      
*                                                                  
         ST    R1,TCBSVCA2        STORE SCREEN TABLE ADDR INTO TCB 
         OI    TCBFLGS7,TCBSVCS   TURN ON SVC SCREENING

Now we go back to key zero and restore SVC screening for the current TCB. We then check the return code to see if the ATTACH was successful. If it failed we can to clean up and exit. If it was successful we copy the screen table address from the current TCB into the newly created TCB and set the TCBSVCS flag to active screening.

          L    R15,0(,R11)        POINT TO RB FOR NEW TASK 
          LM   R0,R3,RBGRSAVE     COPY REGISTERS TO NEW RB 
          STM  R0,R3,RBGRSAVE-RBSECT(R15)                  
          LM   R0,R3,RBGRSAVE+16                           
          STM  R0,R3,RBGRSAVE-RBSECT+16(R15)               
          LM   R0,R3,RBGRSAVE+32                           
          STM  R0,R3,RBGRSAVE-RBSECT+32(R15)

Now we copy the register contents from request block into the RB for the newly created task. This will make the initial register contents of the new task appear the same as if we had not intercepted the ATTACH SVC. It really should not make any difference since contents of the registers other than 1, 13, 14, and 15 are not guarenteed to contain any specific values. Still, by copying the contents of registers 0 through 12 we stay complete compatable with the normal operation of ATTACH.

         TM    ATTCHLST+ATLSTSIZ,X'80'   IS CALER AUTH            
         BO    AUTH040                   YES - NO RESET NEEDED    
*                                                                 
         L     R1,TCBGRS12        GET SVRB ROUTINE R12            
         NI    8(R1),255-X'80'    INDICATE ATTACHING TASK NOT AUTH

We have some attitional cleaup to do. Since we always reissue the ATTACH SVC and since we are always in supervisor mode when we reissue the SVC, ATTACH processing always sets up the new TCB as though it was created by an authorized program. This will cause problems when the new TCB is dispatched. If the caller is not authorized we need to reset a flag bit that is passed to the second half to ATTACH processing. When the new TCB is dispatched the initial execution point is in the ATTACH SVC where a new save area is allocated before passing control to a special entry point in the program loader. The program loader checks this flag bit to know if the caller of ATTACH was authorized or not. Since we reissued the ATTACH SVC this bit is always set. Here we reset it to reflect the state of the caller of the original SVC.

         SLR   R1,R1              ZERO R1                  
         ICM   R1,B'0111',ATSTAIXT  ANY STAI/ESTAI         
         BZ    AUTH040              NO - SKIP              
*                                                          
         L     R1,TCBSTAB         POINT TO SCB CHAIN       
AUTH035  DS    0H                                          
         ICM   R1,B'0111',1(R1)   POINT TO NEXT ENTRY      
         BZ    AUTH040            EXIT IF SCB NOT FOUND    
*                                                          
         USING SCB,R1                                      
*                                                          
         CLC   SCBEXIT+1(3),ATSTAIXT  IS THIS OUR SCB ENTRY
         BNE   AUTH035                NO - TRY NEXT        
*                                                          
         NI    SCBFLGS2,255-(SCBSUPER)  TURN OFF SUPER BIT 
AUTH040  DS    0H

We have one last thing to clean up before we can let the new TCB dispatch. If a STAEI/ESTAI was specified on the ATTACH we need to reset the supervisor mode bit in the STAE Control Block (SCB) if our caller was not authorized. Failre to properly set this bit could allow an unauthorized program to receive control in authorized mode when the ESTAE exit is called. If a STAEI/ESTAEI exit was specified on the ATTACH we loop through the SCB chain to locate the associated SCB and clear the SCBSUPER bit.

         TM    ATTCHLST+ATLSTSIZ,X'40'  SHOULD WE LEAVE NON-DISP 
         BO    AUTH050                  YES - BRANCH             
*                                                                
         STATUS RESET,ND,(R11),(12)                              
AUTH050  DS    0H

Now unless the caller was authorized AND specified the new task should not dispatch we now issue the STATUS macro to reset the task dispatchability status. This will allow the newly created task to begin execution.

FREEEXIT DS    0H                                             
         DROP  R11                                            
         USING TCB,R4                                         
         MODESET EXTKEY=RBT234,WORKREG=2  GET INTO CALLERS KEY
*                                                             
         FREEMAIN R,LV=ATLSTSIZ,A=(R7),SP=229                 
*                                                             
         SPKA  0                  BACK TO KEY ZERO

Now all that is left is to clean up before exiting. First we use MODESET to get back into the caller’s key so we can FREEMAIN the work area we previously allocated with GETMAIN. We then go back to key zero.

         LR    R1,R11             SET TCB ADDRESS        
         LR    R15,R12            SET ATTACH RC          
SVCEXIT  DS    0H                                        
         SPKA  0                  GET INTO KEY ZERO      
         LR    R14,8              RESTORE RETURN ADDRESS 
         BR    R14

Before exiting we need to restore the return values for register 1 and 15 that were previously saved.

         IKJTCB ,   
         IKJRB ,    
         IEZATTCH , 
         IEZJSCB ,  
         IHASCB ,

The control block mapping macros and register equates (not shown here) complete the SVC 42 intercept code.

         ATTACH EP=IFOX00,ECB=ECB                                     
         ST    R1,PTRTCB          SAVE TCB ADDRESS 
         WAIT  1,ECB=ECB                           
         DETACH PTRTCB            DETACH TCB

Now if we replace the LINK=IFOX00 to an ATTACH we can test the SVC 42 intercept logic.

JOB 6912  $HASP373 RUNSVX   STARTED - INIT 12 - CLASS A - SYS TCS3
JOB 6912  20.04.34   0.00.00   0.00.00  0000   RUNSVX    COMPRESS 
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IHARB                    
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IKJRB                    
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IEZXRB                   
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IEZBITS                  
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IKJTCB                   
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 TESTAUTH                 
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IHBERMAC                 
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 WTO                      
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IHBINNRA                 
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 DETACH                   
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 WAIT                     
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 ATTACH                   
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 IHBOPLST                 
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 GETMAIN                  
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 MODESET                  
JOB 6912  SVC 18 R0=00096C68 R1=FFF69718 SAVE                     
JOB 6912  20.04.34   0.00.00   0.00.00  0000   RUNSVX    ASM     
JOB 6912  20.04.34   0.00.00   0.00.00  0000   RUNSVX    ########
JOB 6912  $HASP395 RUNSVX   ENDED

Upon execution we see that SVC 42 was intercepted and SVC screening was propagated since we are still intercepting the FIND SVC calls.

Console Communications

I include this one not so much because I have found it really useful but becuase I think it has a bit of a cool factor.  I first used this back many years ago when I was an operator and would write various utilities for us to use in operations.  Since we were in the computer room with the console it was pretty easy just  use WTOR to make the program interactive with the console.  Back in those days we were batch only and didn’t use TSO.  Using WTOR for communication through the operator console is pretty simple but lacks the cool factor associated with using the MODIFY console command.  So here is how to use MODIFY and STOP to communicate with a running program.

First we need to get the address of the Communications Parameter List (mapped by the IEZCOM macro).  The COM parameter list consists of two words.

COMECBPT DS    A       Address of ECB for STOP/MODIFY
COMCIBPT DS    A       Address of Command Input Buffer

To get the address of the COM parameter area we can use the EXTRACT macro.

         EXTRACT COMPTR,FIELDS=COMM    GET POINTER TO COMM FIELDS

COMPTR is a fullword where the address of the COM parameter area will be stored. We request the COM parameter area by specifying FIELDS=COMM.

         L     R1,COMPTR          POINTER TO COMM FIELDS 
         LA    R2,4(,R1)          CIB ORIGIN             
         L     R3,0(,R2)          PONTER TO FIRST CIB    
         LTR   R3,R3              ANY START CIB PRESENT  
         BZ    SETCIB             NO - CONTINUE

Next we load the address of the COM parm area into register 1. Now we have to check to see if there is a Command Input Buffer (CIB) related to a START command. If we are running as a Started Task there should be a CIB, otherwise there is no CIB and the pointer is zero.

         QEDIT ORIGIN=(R2),BLOCK=(R3)   FREE START CIB

If there is a CIB as the result of a START command we need to free the CIB. For this we use the QEDIT macro and pass two parameters. ORIGIN refers the the address of the COMCIBPT field (the second word in the COM parmameter list) and BLOCK points the the CIB we wish to free.

SETCIB   DS    0H                                                     
         QEDIT ORIGIN=(R2),CIBCTR=1     SET CIB LIMIT TO ONE AT A TIME

Now we set a limit on how many CIBs may be queued to our job at one time. Initially this value is zero which means that MODIFY commands will not be accepted by our job. We want to allow one CIB to be queued at a time so we set the limit using the QEDIT macro. Here we specify the ORIGIN (again the address of the COMCIBPT field) and specify a limit with the CIBCTR parameter.

LOOP     DS    0H                                    
         L     R1,COMPTR          COMM FIELDS        
         LA    R2,0(,R1)          ECB ADDRESS PTR    
         L     R3,0(,R2)          ECB ADDRESS        
*                                                    
         WAIT  1,ECB=(R3)         WAIT FOR A COMMAND

Now we will wait for a command from the console. We do this by waiting on the ECB pointed to by the COMECBPT field. We could also be doing some work and check to see if the ECB has been posted to interrupt whatever we are currenty doing. Here we just wait for a command.

         L     R1,COMPTR          POINTER TO COMM FIELD 
         LA    R2,4(,R1)          CIB ORIGIN            
         L     R3,0(,R2)          PONTER TO FIRST CIB

When the ECB is posted we resume execution and get the address of the CIB. The CIB is mapped by the IEZCIB macro and contains the following fields.

CIBNEXT  DS    A                  POINTER TO NEXT CIB ON CHAIN OR ZERO IF LAST
CIBVERB  DS    X                  VERB INDICATING TYPE OF COMMAND
*                                 X'04' - START, X'40' - STOP, X'44' - MODIFY
CIBLEN   DS    X                  LENGTH IN DOUBLEWORDS OF CIB
         DS    XL4                Reserved
CIBASID  DS    H  
CIBCONID DS    X                  CONSOLE ID - FROM WHERE COMMAND WAS ISSUED
         DS    X                  Reserved
CIBDATLN DS    H                  LENGTH, IN BYTES, OF CIB DATA
CIBDATA  DS    0C                 DATA FROM MODIFY COMMAND

The VERB tells us in the CIB was created as a result of a START, STOP, or MODIFY console command. CIBDATALN is the length of data associated with the command. CIBDATA is a variable length field that contains the data from the START or MODIFY command.

         CLI   4(R3),X'44'        IS IT A MODIFY COMMAND 
         BE    MODIFY                                    
*                                                        
         CLI   4(R3),X'40'        IS IT A STOP COMMAND   
         BE    STOP                                      
*                                                        
         WTO   '***  UNKNOWN CIB TYPE ***',ROUTCDE=(1,11)
         B     FREECIB

Now we check the VERB to determine what type of command we are dealing with. We only expect to find either a STOP or a MODIFY command.

MODIFY   DS   0H                                                 
         WTO   '***  MODIFY COMMAND RECEIVED ***',ROUTCDE=(1,11) 
*                                                                
         LH    R5,14(,R3)         GET COMMAND LENGTH             
         LA    R6,16(,R3)         POINT TO COMMAND

Here we process a MODIFY command. We point to the data and get the data length from the CIB.

         LR    R1,R5              COPY LENGTH  
         BCTR  R1,0               SUBTRACT ONE 
         MVC   WORK(4),=C'*** '                
         EX    R1,MODMVC                       
MODMVC   MVC   WORK+4(1),0(R6)                 
         LA    R1,WORK+4                       
         AR    R1,R5                           
         MVC   0(4,R1),=C' ***'                
         LA    R1,WORK                         
         LA    R0,8(,R5)                       
         BAL   R14,WTO                         
*                                              
         B     FREECIB

Next we copy the data into a message area and BAL to a routine that will WTO the message to the console.

WTO      DS    0H                                  
         STM   R14,R12,12(R13)                     
         LA    R3,SAVEA2                           
         ST    R13,4(,R3)                          
         ST    R3,8(,R13)                          
         LR    R13,R3                              
*                                                  
         LR    R10,R0             SAVE LENGTH      
         LR    R11,R1             SAVE PTR TO TEXT 
*                                                  
         LA    R1,1                                
         CR    R10,R1                              
         BL    WTO020                              
*                                                  
         LA    R1,80              MAX LEN          
         CR    R10,R1                              
         BNH   WTO010
*                    
         LR    R10,R1

Here is the routine to issue the WTO. First we save the caller’s registers, set up a new save area, and then check the length of the message.

WTO010   DS    0H                      
         MVC   WTOWORK(4),=X'00008000' 
         LA    R1,4(,R10)              
         STH   R1,WTOWORK              
         BCTR  R10,0                   
         EX    R10,WTOMVC              
*WTOMVC  MVC   WTOWORK+4(1),0(R11)     
         LA    R1,WTOWORK              
         LA    R1,5(R10,R1)            
         MVC   0(4,R1),=X'00008020'

Now we build the SVC 35 parameter list.

LA    R1,WTOWORK      
         SVC   35              
*                              
WTO020   DS    0H              
         L     R13,4(,R13)     
         LM    R14,R12,12(R13) 
         BR    R14

Now we point to the parameter list, issue the WTO SVC, and then return to the caller.

STOP     DS   0H                                               
         WTO   '***  STOP COMMAND RECEIVED ***',ROUTCDE=(1,11) 
         B     EXIT

If the VERB indicates a STOP command we issue a WTO and exit.

FREECIB  DS    0H                                        
         L     R1,COMPTR          POINTER TO COMM FIELDS 
         LA    R2,4(,R1)          CIB ORIGIN             
         L     R3,0(,R2)          PONTER TO FIRST CIB    
*                                                        
         QEDIT ORIGIN=(R2),BLOCK=(R3)   FREE THE CIB     
*                                                        
         B     LOOP

Once we have processed a MODIFY command we need to free the CIB so our program can accept another modify command. We free it using QEDIT the same way we did with the START CIB.

JOB 6920  $HASP373 CIB01    STARTED - INIT 12 - CLASS A - SYS TCS3  
          f CIB01,HELLO                                             
JOB 6920  +***  MODIFY COMMAND RECEIVED ***                         
JOB 6920  +*** HELLO ***                                            
          f cib01,This is a TEST                                    
JOB 6920  +***  MODIFY COMMAND RECEIVED ***                         
JOB 6920  +*** THIS IS A TEST ***                                   
          f cib01,Parameters to pass to the program                 
JOB 6920  +***  MODIFY COMMAND RECEIVED ***                         
JOB 6920  +*** PARAMETERS TO PASS TO THE PROGRAM ***                
          p cib01                                                   
JOB 6920  +***  STOP COMMAND RECEIVED ***                           
JOB 6920  14.09.40   0.00.45   0.00.00  0000   CIB01     MVSSP      
JOB 6920  14.09.40   0.00.45   0.00.00  0000   CIB01     ########   
JOB 6920  $HASP395 CIB01    ENDED

And here is some sample output from running the program and communicating with it using MODIFY and STOP.