TITLE QSRIPC -- IPC Handler for QUASAR SUBTTL Larry Samberg C.D. O'Toole 7 Nov 76 ;***Copyright (C) 1974, 1975, 1976, 1977, Digital Equipment Corp., Maynard, MA.*** SEARCH QSRMAC ;PARAMETER FILE PROLOGUE(QSRIPC) ;GENERATE THE NECESSARY SYMBOLS ;GLOBAL ROUTINES IN THIS MODULE USE ALL ACCUMULATORS EXCEPT: ; P1,P2,P3,P4, AND M ;QSRIPC DOES NOT CONTAIN ANY STOPCD'S ;MODULE STORAGE IPCASV: BLOCK 1 ;ASSOCIATED VARIABLE FOR NEXT RECEIVE IPCPND: EXP -1 ;SET TO -1 WHEN A RECEIVE INTERRUPT IS IGNORED. SUBTTL Global Entry Points in QSRIPC INTERN C$INIT ;Initialize the IPC Handler INTERN C$GET ;Get next message from the IPC queue INTERN C$RAPK ;Receive all outstanding IPCF packets INTERN C$PUT ;Put IPC core back in free list INTERN C$INT ;Interrupt Level Entry INTERN C$SEND ;Send an IPCF Message INTERN C$RSND ;Re-send messages that failed SUBTTL C$INIT -- IPC Handler Initialization ;C$INIT SETS UP FOR INITIAL QUERRY AND ESTABLISHES A PID FOR [SYSTEM]QUASAR C$INIT: MOVEI S1,SP.QSR ;CREATE A [SYSTEM]QUASAR PUSHJ P,I$EPID## ;ASK [SYSTEM]IPCC MOVEM S1,G$QPID## ;REMEMBER OUR PID POPJ P, ;AND RETURN SUBTTL C$GET -- Routine to return next IPC message ;RETURNS THE NEXT MESSAGE FROM THE IPCF RECIEVE QUEUE. ; RETURNS WITH "AP" POINTING TO THE MESSAGE. IF ; AP CONTAINS ZERO ON RETURN, NO REQUESTS ARE IN THE ; QUEUE. C$GET: PUSHJ P,C$RAPK ;RECEIVE ALL OUTSTANDING PACKETS LOAD AP,,QH.PTF ;GET POINTER TO 1ST ENTRY PJUMPE AP,.POPJ## ;RETURN IF NONE MOVEI H,HDRIPC## ;LOAD H PJRST M$DLNK## ;DLINK THE ENTRY AND RETURN SUBTTL C$RAPK -- Receive all outstanding Packets ;CALLED TO GET ANY MESSAGES IN OUR RECEIVE QUEUE IF IPCPND HAS BEEN SET C$RAPK: SKIPL IPCPND ;ANYTHING PENDING? POPJ P, ;NO, RETURN PUSHJ P,I$NOIN## ;TURN OFF INTERRUPTS ZERO IPCPND ;CLEAR PENDING FLAG PUSHJ P,I$IPQ## ;QUERY THE QUEUE JUMPE S1,.POPJ## ;NOTHING THERE, SKIP THE RECEIVE MOVEM S1,IPCASV ;ELSE SAVE ASSOCIATED VARIABLE PJRST IPCRCV ;EMPTY OUR RECEIVE QUEUE SUBTTL C$PUT -- Routine to return free IPC core ;THIS ROUTINE IS CALLED TO PLACE AN IPC QUEUE ENTRY BACK INTO ; THE FREE SPACE. A CHECK IS MADE TO SEE IF IT IS A PAGED ; MESSAGE, AND IF SO THE PAGE IS RELEASED FIRST. CALLED ; WITH AP POINTING TO THE ENTRY. C$PUT: MOVEI H,HDRIPC## ;SET UP H FOR M$PFRE MOVE S1,IPCFLG(AP) ;GET FLAGS TXNN S1,IP.CFV ;IS IT PAGED? PJRST M$PFRE## ;NO, RETURN VIA PFRE MOVE T1,AP ;YES, SAVE AP LOAD AP,IPCMES(AP),IPM.AD ;GET THE PAGE NUMBER PUSHJ P,M$RELP## ;RELEASE THE PAGE MOVE AP,T1 ;RESTORE AP PJRST M$PFRE## ;AND RETURN VIA PFRE SUBTTL C$INT -- Interrupt Level Entry ;SAVES ALL NECESSARY ACS AND CALLS IPCRCV TO RECEIVE ALL OUTSTANDING ; PACKETS. ; ;IF THE INTERRUPTED PC IS IN THE MEMORY MANAGER, THE INTERRUPT ; IS IGNORED TO AVOID ANY RACE CONDITIONS. C$INT: DMOVEM S1,INT.A ;SAVE S1 AND S2 FIRST MOVEM P,INT.P ;SAVE SOMEBODYS P MOVE P,[IOWD INTPSZ,INT.B] ;SET UP OUR OWN PUSHDOWN STACK SKIPGE IPCPND ;IF "PENDING" IS SET, JRST INT.4 ; IGNORE THE INTERRUPT PUSHJ P,I$OKIN## ;OK TO PROCESS INTERRUPT JUMPN S1,INT.1 ;JUMP IF OK TO PROCESS IT SETOM IPCPND ;MARK TO LOOK AGAIN LATER JRST INT.4 ;DISMISS IT NOW INT.1: PUSH P,AP ;SAVE AP PUSH P,H ;SAVE H PUSH P,TEMP ;SAVE TEMP INT.2: PUSHJ P,I$GMIS## ;GET MESSAGE INTERRUPT STATUS JUMPE S1,INT.3 ;0, NO MESSAGE THERE MOVEM S1,IPCASV ;SAVE ASSOCIATED VARIABLE PUSHJ P,IPCRCV ;RECEIVE A PACKET INT.3: POP P,TEMP ;RESTORE TEMP POP P,H ;RESTORE H POP P,AP ;RESTORE AP SKIPA ;SKIP DEFER COUNTER INT.4: $COUNT (IPCD) ;NO. OF DEFERED IPCF INTERRUPTS $COUNT (IPCI) ;TOTAL NUMBER OF IPCF INTERRUPTS PUSHJ P,I$POST## ;AND POST THE INTERRUPT DMOVE S1,INT.A ;GET S1 AND S2 BACK MOVE P,INT.P ;RESTORE INTERRUPTED STACK JRST I$DBRK## ;DISMISS THE INTERRUPT INT.A: BLOCK 2 ;SAVED S1 AND S2 DURING INTERRUPT INT.B: BLOCK ^D20 ;STACK TO BE USED AT INTERRUPT LEVEL INTPSZ==.-INT.B ;LENGTH OF IT INT.P: BLOCK 1 ;INTERRUPTED P (STACK) SUBTTL IPCRCV -- Routine to Receive IPCF Packets ;THIS ROUTINE IS CALLED WITH LOCATION "IPCASV" CONTAINING THE ; ASSOCIATED VARIABLE OF THE FIRST MESSAGE TO BE RECEIVED. ; IT LOOPS THROUGH AND RECEIVES ALL OUTSTANDING IPCF MESSAGES. ; IT IS CALLED AT BOTH INTERRUPT LEVEL AND PROGRAM LEVEL. ; ;USES S1,S2,H,AP IPCRCV: ZERO IPCPND ;CLEAR PENDING FLAG MOVEI H,HDRIPC## ;LOAD ADDRESS OF IPCF QUEUE HDR IPCR.1: PUSHJ P,M$GFRE## ;GET A FREE CELL ZERO IPCFLG(AP) ;CLEAR THE OLD FLAG WORD ZERO IPCR.A ;CLEAR PAGE WORD MOVE S1,IPCASV ;GET THE ASSOCIATED VARIABLE TXNE S1,IP.CFV ;SKIP IF NOT PAGED JRST IPCR.2 ;PAGED, BRANCH MOVEI S1,IPCDAT(AP) ;POINT TO FIRST WORD OF SHORT MESSAGE HRL S1,G$MPS## ;GET SIZE OF MESSAGE IN LH MOVEM S1,IPCMES(AP) ;AND STORE IN IPC HEADER JRST IPCR.4 ;RECEIVE THE PACKET AND RETURN IPCR.2: PUSH P,AP ;SAVE ADDRESS OF QUEUE ENTRY PUSHJ P,M$NXPG## ;GET ADDRESS OF A NON-EX PAGE MOVEM AP,IPCR.A ;AND STORE THE PAGE NUMBER JUMPN AP,IPCR.3 ;OK IF GOT A PAGE FOR THE MESSAGE SETOM IPCPND ;SET THE REQUEST-PENDING FLAG POP P,AP ;LOAD ADDRESS OF THE IPC CELL PJRST M$PFRE## ;AND RETURN IT TO THE FREE SPACE IPCR.3: POP P,S2 ;GET POINTER TO QUEUE ENTRY BACK HRLI AP,1000 ;AND THE SIZE MOVEM AP,IPCMES(S2) ;STORE IN IPCF HEADER MOVX S1,IP.CFV ;GET PAGE-MODE BIT MOVEM S1,IPCFLG(S2) ;AND STORE IT IN FLAG WORD MOVE AP,S2 ;AND GET THE ADDRESS OF THE QUEUE ENTRY IPCR.4: MOVX S1,IP.CFP!IP.TTL ;WANT TO SEE CALLERS PRIVS AND TRUNCATE IORM S1,IPCFLG(AP) ;SO ASK TO SEE SENDERS IP.CFP MOVE S1,G$QPID## ;GET MY PID MOVEM S1,IPCRCR(AP) ;AND SAVE IT AS RECEIVER'S PID MOVEI S1,IPCRSZ ;LOAD THE HEADER SIZE MOVEI S2,IPCFLG(AP) ;AND THE ADDRESS PUSHJ P,I$IPR## ;RECIEVE IT $COUNT (RIPC) MOVEM S1,IPCASV ;SAVE ASSOC. VAR. FOR THE NEXT ONE PUSHJ P,M$ELNK## ;LINK IT IN AT THE END SKIPE AP,IPCR.A ;GET PAGE NUMBER AND SKIP IF NOT THERE PUSHJ P,M$IPRC## ;AND TELL QSRMEM THAT IT NOW EXISTS SKIPE IPCASV ;ANYTHING LEFT TO DO? JRST IPCR.1 ;YES, LOOP POPJ P, ;NO, RETURN IPCR.A: BLOCK 1 ;PAGE NUMBER IF PAGED RECEIVE SUBTTL C$SEND -- Routine to send IPCF Message ;C$SEND ROUTINES ARE CALLED WITH AP POINTING TO THE PACKET DESCRIPTOR ; BLOCK FOR THE MESSAGE TO BE SENT. THE MESSAGE IS SENT, AND ; IF IT WAS PAGED, M$RELP IS CALLED TO DESTROY THE PAGE. ; LEFT HALF OF AP CONTAINS FLAGS FOR THIS SEND. C$SEND: MOVEM AP,SEND.A ;SAVE AP FOR LATER MOVE S1,.IPCFL(AP) ;GET THE FLAG WORD TXNN S1,IP.CFV ;PAGE MODE? JRST SEND.1 ;NO, NO PROBLEM HRRZ AP,.IPCFP(AP) ;GET PAGE NUMBER PUSHJ P,M$IPSN## ;NOTIFY THE MEMORY MANAGER MOVE AP,SEND.A ;GET AP BACK SEND.1: MOVE S2,G$QPID## ;ASSUME FROM [SYSTEM]QUASAR SKIPN .IPCFS(AP) ;SENDER SUPPLIED MOVEM S2,.IPCFS(AP) ;NO, STORE AS SENDER'S PID TXNE AP,IPS.TF ;SKIP PASS OVER IPS QUEUE JRST SEND.4 ;YES, GO TRY TO SEND IT LOAD S1,,QH.PTF ;GET PTR TO 1ST ITEM IN IPS QUEUE LOAD S2,.IPCFR(AP) ;GET THE PID WE'RE SENDING TO SEND.2: JUMPE S1,SEND.4 ;NOTHING LEFT IN IPS QUEUE, DONE CAME S2,IPCRCR(S1) ;SAME GUY?? JRST SEND.3 ;NO, KEEP LOOPING TXNE AP,IPS.ID ;IGNORE IF DUPLICATE IN IPS QUEUE TXO AP,IPS.IF ;YES, LITE IGNORE ALL FAILURES MOVEI S1,IPE.RQ ;YES, LOAD A PHONY ERROR CODE JRST SNDFAI ;AND QUEUE UP THE MESSAGE SEND.3: LOAD S1,.QELNK(S1),QE.PTN ;GET POINTER TO NEXT JRST SEND.2 ;AND KEEP LOOPING SEND.4: MOVEI S1,IPCHSZ ;LOAD THE HEADER SIZE HRRZ S2,AP ;AND THE ADDRESS PUSHJ P,I$IPS## ;SEND IT JUMPL S2,SNDFAI ;S2=-1 MEANS FAILURE $COUNT (SIPC) MOVE S2,.IPCFL(AP) ;GET THE FLAG WORD TXNN S2,IP.CFV ;PAGE-MODE SEND? POPJ P, ;NO, JUST RETURN HRRZ AP,.IPCFP(AP) ;GET THE PAGE NUMBER PJRST M$RELP## ;RELEASE THE PAGE AND RETURN SEND.A: BLOCK 1 ;STORE AP AROUND CALLS TO QSRMEM SUBTTL SNDFAI -- IPCF Send Failure ;SNDFAI IS CALLED WHEN THE IPCF SEND ROUTINE C$SEND GETS THE ; ERROR RETURN FROM THE IPCF SEND ROUTINE. IF THE ERROR ; IS RECOVERABLE AT SOME POINT, THE MESSAGE IS LINKED TO ; THE END OF THE IPS QUEUE FOR A RETRY LATER, OTHERWISE ; THE MESSAGE IS SIMPLY FORGOTTEN ABOUT. ; ;IF THE SEND FAILURE IS DUE TO AN INVALID RECEIVER, WE IGNORE ; THE FAILURE, AND IF THE INTENDED RECEIVER WAS A KNOWN ; COMPONENT, WE ATTEMPT TO KILL THE PSB. ; ;ON ENTERING, S1 CONTAINS THE ERROR CODE AND AP CONTAINS ADDRESS OF ; PACKET DESCRIPTOR BLOCK OF THE BAD SEND (ALSO IN "SEND.A"). SNDFAI: $COUNT (IPCF) CAIN S1,IPE.SF ;SYSTEM FREE SPACE USED UP? JRST SNDF.1 ;YES, TRY AGAIN LATER TXNE AP,IPS.IF ;IGNORE FAILURES SETOB S1,.IPCFR(AP) ;YES, PHONY PID AND ERROR CODE CAIE S1,IPE.SQ ;MY SEND QUOTA FULL? CAIN S1,IPE.RQ ;OR HIS REC QUOTA FULL? JRST SNDF.1 ;YES, QUEUE UP THE MESSAGE ;HERE IF WE WANT TO IGNORE THE ERROR. RETURN THE PAGE (IF IT ; WAS A PAGED SEND), AND IF THE RECEIVER'S PID IS NON-ZERO ; ATTEMPT TO KILL HIS PSB. $COUNT (IPCU) PUSH P,.IPCFR(AP) ;SAVE RECEIVER'S PID MOVE S1,.IPCFL(AP) ;GET FLAG WORD TXNN S1,IP.CFV ;IS IT PAGED? JRST SNDF.0 ;NO, NOTIFY EVERYBODY HRRZ AP,.IPCFP(AP) ;YES, GET PAGE NUMBER PUSH P,AP ;SAVE AP PUSHJ P,M$IPRC## ;PRETEND THAT WE REC'ED IT POP P,AP ;GET PAGE NUMBER BACK PUSHJ P,M$RELP## ;AND RELEASE IT SNDF.0: POP P,S1 ;GET PID BACK PJRST G$SFAL## ;NOW TELL EVERYBODY ;CONTINUED FROM PREVIOUS PAGE ;HERE IF WE CAN QUEUE UP THE MESSAGE FOR A LATER RETRY SNDF.1: MOVEI S1,^D15 ;SET A SLEEP TIME OF 15 SECS PUSHJ P,I$SVAL## ; SO THAT RE-SEND HAPPENS QUICKLY SAVE H ;SAVE THE QUEUE HEADER MOVEI H,HDRIPS## ;LOAD ADR OF IPS HEADER PUSHJ P,M$GFRE## ;GET A FREE CELL MOVE S1,SEND.A ;GET ADDRESS OF PDB OF BAD SEND MOVS S2,S1 ;MAKE SOURCE OF BLT POINTER HRRI S2,IPCFLG(AP) ;SET DEST OF BLT BLT S2,IPCMES(AP) ;BLT THE PDB MOVE S2,.IPCFL(S1) ;GET THE FLAG WORD TXNE S2,IP.CFV ;IS IT PAGED? JRST SNDF.2 ;YES, HANDLE THE PAGE MOVS S2,.IPCFP(S1) ;NO, GET ADR,,SIZE HRRI S1,IPCDAT(AP) ;GET 0,,DEST HRRM S1,IPCMES(AP) ;SAVE IT AS ADR OF MSG IN PDB HLL S1,S2 ;GET SOURCE,,DEST ADDI S2,-1(S1) ;GET END-OF-BLT ADR BLT S1,(S2) ;BLT THE MESSAGE PJRST M$ELNK## ;LINK INTO IPS QUEUE SNDF.2: PUSH P,IPCMES(AP) ;SAVE ADR WORD PUSHJ P,M$ELNK## ;LINK ENTRY INTO IPS QUEUE POP P,AP ;GET LEN,,ADR BACK HRRZS AP ;JUST GET ADR (PAGE NO.) PJRST M$IPRC## ;NOTIFY "MEM" AND RETURN SUBTTL C$RSND -- Resend Unsendable Messages ;C$RSND IS CALLED EACH TIME THRU THE MAIN LOOP. IT ATTEMPTS TO ; RESEND EVERYTHING IN THE "IPS" QUEUE AGAIN. C$RSND: PUSHJ P,.SAVE1## ;SAVE P1 FIRST LOAD P1,,QH.PTF ;LOAD PTR TO 1ST IN IPS QUEUE ZERO ;MAKE BELIEVE THERE'S NOTHING THERE RSND.1: PJUMPE P1,.POPJ## ;NOTHING THERE (FOR REAL), RETURN MOVEI AP,IPCFLG(P1) ;POINT AP TO THE MSG PDB PUSHJ P,C$SEND ;AND SEND THE MESSAGE MOVE AP,P1 ;COPY THE ADDRESS OF THE CELL LOAD P1,.QELNK(P1),QE.PTN ;GET THE POINTER TO THE NEXT ONE MOVEI H,HDRIPS## ;INSURE A PROPER HEADER PUSHJ P,M$PFRE## ;AND PFRE THE CELL. ;**WARNING** ; DO NOT CALL DLNK OR RFRE!!! JRST RSND.1 ;AND LOOP END