.title Entrap .ident *01.02* ;+ ; **-Entrap-AST / SST Interface and Autoload Context Preservation Routine ; ; Version 01.02 ; ; Dave A. Klotzbach April 29, 1982 ; ; This routine is called from an AST or SST transfer vector set up by the ; calling program. The vector has the following format: ; ; +-------------------------------+ ; 0 | | ; +-- JSR R1,@#ENTRAP --+ ; 2 | | ; +-------------------------------+ ; 4 | Number Of Items On Trap Stack | See Note, Below ; +-------------------------------+ ; 6 | AST/SST Routine Entry Address | ; +-------------------------------+ ; ; Inputs: ; ; r1 =Address of 2nd half of trap vector ; 0(sp)=Saved r1 contents ; 2(sp)=Remainder of AST / SST stack (depends on the type of trap) ; ; Outputs: ; ; Saves the current Autoload Overlay mapping context (if the task is ; overlaid) and calls the specified AST or SST service routine. Upon ; re-entry it restores the mapping context (if necessary), cleans up ; the stack, and effects an AST or SST exit. ; ; Note: ; ; The COUNT element (3rd word) in the transfer vector must be ; initialized with care. For an AST, it is the number of excess ; trap-specific parameters. That is, the number does not include the ; common 4 words in the AST stack (Event Flag Mask Word, PS, PC, and ; $DSW). For an SST, the value is the negative of the total number of ; words on the stack, including the usual 2 words (PS and PC). ; ; This subroutine is usually called from an AST / SST vector set up by the ; calling program. This vector can be expressed in a C structure as follows : ; ; typedef struct{ ; int JSR_R1; /* the actual command to call routine */ ; int (*entrap)(); /* the routine to be called */ ; int count; /* the number of "active" arguments */ ; int (*srvrtn)(); /* user defined subroutine */ ; } TRAP_VECTOR; ; ; A QIOW AST vector is then initialized as follows : ; ; static TRAP_VECTOR qiow_ast = { 04137,&entrap,1,&ast_routine }; ; ; Alternatively, the vector can be set up in MACRO-11 : ; ; .MACRO TRPVEC SRVRTN,COUNT ; jsr r1,@#entrap ;transfer to entrap first ; .word COUNT ;system trap stack code word ; .word SRVRTN ;trap service routine addr ; .ENDM TRPVEC ; ; A memory-protect SST vector would then be initialized as follows : ; ; V$MPRO: TRPVEC MEMSST,-5 ;SET UP THE MEMORY-PROTECT SST ROUTINE VECTOR ; ; The work area is located in the $$OVDT psect and is structured as follows : ; ; +-------------------------------+ ; 0 | Overlay Load LUN | .novly, n.ovly * ; +-------------------------------+ ; 2 | Address of First Segment Desc | .nstbl, n.stbl + ; +-------------------------------+ ; 4 | Overlay Load | .niost, n.iost ; +--- I/O ---+ ; 6 | Status Block | ; +-------------------------------+ ; 10 | Overlay Load Error Subroutine | .naler, n.aler + ; +-------------------------------+ ; 12 | Segment Descriptor Size | .nszsg, n.szsg * ; +-------------------------------+ ; 14 | Load and Map Segment Routine | .nrdsg, n.rdsg + ; +-------------------------------+ ; 16 | Unmap Segment(s) Routine | .nmrks, n.mrks + ; +-------------------------------+ ; 20 | Total Number Of Task Segments | .nsegs, n.segs ! ; +-------------------------------+ ; 22 | Top Address Of Segment Stack | .nroot, n.root ! ; +-------------------------------+ ; 24 | Segment Stack Pointer | .nstpt, n.stpt ! ; +-------------------------------+ ; ; * - The Overlay Load LUN and the Segment Descriptor Size words are ; filled in by the Task Builder. The Segment Descriptor size is 6, ; 8, or 9 words long, depending on whether manual loading and ; memory-resident overlays are used. The Task Builder Automatically ; allocates a Logical Unit, assigns the load device to it, and ; fills in the number. ; ; + - The address of the first Segment Descriptor, and the addresses of ; the Overlay Load Failure Routine, the Load and Map Segment, and ; Unmap Conflicting Segment(s) Routines are filled in at assembly ; time by the Ovdat module. ; ; ! - The Top Address of Segment Stack and Segment Stack Pointer are ; filled in at assembly time by this module. The Number of Task ; Segments is initialized at run-time by the Ovlini routine. The ; Segment Stack area is allocated at assembly time by this module ; ule, with a default size of 12. words. This is adequate for a ; task with 4 overlaid segments to have an overlaid SST routine ; interrupt an overlaid AST routine which has itself interrupted an ; overlaid task-level routine. These words are optional and present ; only if this module is explicitly included in the Task-Build ; command file (E.g. lb:[1,1]syslib/lb:endat). The end of the ; overlay work area is determined from the address of the $$OVDU ; psect. ; ; The Segment Stack area is located in the $$STCK psect, as follows : ; ; +-------------------------------+ ; | 1st Segment's Root Address | <- .nroot ; +-------------------------------+ ; | 2nd Segment's Root Address | ; +-------------------------------+ ; . ; . ; . ; +-------------------------------+ ; | Nth Segment's Root Address | ; +-------------------------------+ ; | Empty | ; +-------------------------------+ ; . ; . ; . ; +-------------------------------+ ; | Empty | ; +-------------------------------+ ; | Nth Set Of N Words Of | <- .nstpt, while running ; +--- Saved Segment ---+ ; | Descriptor Addresses | ; +-------------------------------+ ; . ; . ; . ; +-------------------------------+ ; | 2nd Set Of N Words Of | ; +--- Saved Segment ---+ ; | Descriptor Addresses | ; +-------------------------------+ ; | 1st Set Of N Words Of | ; +--- Saved Segment ---+ ; | Descriptor Addresses | ; +-------------------------------+ ; <- .nstpt, initially ; ; The Segment Stack area may be enlarged by means of the Task-Builder's ; EXTSCT option. For example, ; ; TKB>extsct=$$stck:20 !make the Segment Stack 28. words long. ;- .mcall alodf$, astx$s, dsar$s, enar$s alodf$ ; Define the segment descriptor symbols .globl .nsegs ; Force the autoload extensions to load .list meb .nlist toc .page .psect $$resl Entrap:: Restra:: mov r0,-(sp) ; Save r0 mov (r1)+,-(sp) ; Save the code number; call ovfout ; Find all of the overlay segments currently maped call @0(r1) ; Call the users service routine call ovmap ; Restore previous context. mov 2(sp),r0 ; Restore R0 mov 4(sp),r1 ; Restore R1 asl (sp) ; Convert Code to byte count bvs 5$ ; Trying to do a "Cluster" call ? bge 3$ ; Do an ast 100$. sub (sp),sp ; Fix sst stack tst (sp)+ ; Copied from the original rti ; And continue execution. 3$: add (sp),sp ; add #6,sp ; Fix the stack astx$s ; Ast ; ; Else all hell breaks loose. ; 5$: iot .page .sbttl OVFOUT - Find the outer/ upper most segment mapped ;+ ; ** OVFOUT - Find the outer/uppermost segment currently mapped ; ; This routine in conjunction with "ovlini" and "ovfix", establish And ; maintain the mapping for a system using ast/sst's. This routine finds ; which of the segments on each of the "root" segments are mapped. By ; knowing this information it will be possible to reconstruct the mapping ; thread back out to the functions in effect at this time. ; ;- OVFOUT:: call $saval ; Save all of the registers. mov @#n.ovpt,r0 ; Get the address of the work area beq 100$ ; EQ - There is no work area tst n.segs(r0) ; Has it been initialized? bne 1$ ; NE - Yes it has call ovlini ; Initialize the overlays. 1$: mov n.root(r0),r2 ; Point to the segment work area mov n.stpt(r0),r1 ; Get the current stack pointer mov n.segs(r0),r4 ; Number of roots to test 2$: mov (r2)+,r3 ; Get a address of the root segment. 6$: mov r3,r5 ; Save the entry pointer 3$: bit #ss.nld,(r3) ; Is this segment mapped? bne 4$ ; NE - no tst s.lkup(r3) ; Is there a higher level? beq 7$ ; EQ - no, that's it for this segment mov s.lkup(r3),r3 ; Go to the next higher level br 6$ ; Look at that one 4$: mov s.lknt(r3),r3 ; Link to the next cmp r3,r5 ; Is this the one we started on? bne 3$ ; NE - no, go traipse thru that list mov s.lkdn(r3),r3 ; Previous level was highest mapped. If window ; isn't mapped at all, this will be a zero. 7$: mov r3,-(r1) ; Push this descriptor address cmp r1,r2 ; Have we a stack under flow? bhi 10$ ; Still safe. iot ; Off we go into the wild blue yonder. 10$: sob r4,2$ ; Continue? mov r1,n.stpt(r0) ; Save the current stack pointer 100$: return .page .sbttl OVLINI - Overlay support initialization ;+ ; ** ovlini - Initialize the overlay/ast support structures. ; ; This routine will initialize the control variables for the modified ; overlay system. In this system it will be possible for the programmer to ; use both overlays and AST/SST's in the same program. ; ; Ovlini calls $saval so it will not disrupt any of the registers. ; ;- OVLINI:: call $saval ; Save all of the registers mov @#n.ovpt,r0 ; Get the work area pointer ; beq 100$ ; If no overlays then exit. mov n.stbl(r0),r1 ; Point to the first segment descriptor mov n.root(r0),r2 ; Point to the root of the segment heap. 1$: tst (r1) ; Is this a real segment? beq 100$ ; EQ - No so we are done. tst s.lkdn(r1) ; Is this a root segment? bne 2$ ; NE - No so get next segment mov r1,(r2)+ ; Save the root segment inc n.segs(r0) ; Count it 2$: add n.szsg(r0),r1 ; Point to the next segment br 1$ ; And try the next one 100$: return ; And quit. .page .sbttl OVMAP ;+ ; ** OVMAP - Map the overlays back in with out calling them ; ; This routine is virtually the same as the one in $auto with the ; exception that it will not call the routine at the outer most level when ; complete. ;- ovmap:: call $saval ; Save all of the registers dsar$s ; Don't let an AST interrupt an SST mov @#$dsw,-(sp) ; Save the status for later mov @#n.ovpt,r0 ; Get the overlay work space pointer mov n.stpt(r0),r1 ; Point to the first segment to load mov n.segs(r0),r4 ; Get the number of segments to map. 1$: mov (r1)+,r2 ; Get the segment to be loaded bit #ss.nld,(r2) ; Is this segment already loaded? beq 2$ ; EQ - Segment loaded get the next one call @n.mrks(r0) ; Clear all branches in the way call lbranch ; Load this branch 2$: sob r4,1$ ; And continue till done mov r1,n.stpt(r0) ; Restore stack pointer cmp (sp)+,#is.suc ; Were ASTs actually disabled earlier ? bne 3$ ; NE - no, they had already been disabled enar$s ; Otherwise, re-enable their recognition 3$: return ; ; ; Load overlay segment branch ; lbranch: call $saval ; Save the regs. 101$: clr r3 ; Let $rdseg use the default flag clr r4 ; And iosb clr r5 ; And ast tst s.size(r2) ; Is this a zero length segment? bne 102$ ; NE - obviously not. bic #ss.nld,(r2) ; It's as good as loaded br 103$ ; 102$: call @n.rdsg(r0) ; Load or map the segment bcc 103$ ; CC - all done call @n.aler(r0) ; Call the error handling routine br 101$ ; And try again 103$: mov s.lkdn(r2),r2 ; Move a step closer to the root beq 104$ ; EQ - We are at the root bit #ss.nld,(r2) ; Is this one loaded? bne 101$ ; Ne - No so go load it br 103$ ; Else find the next one 104$: return ; All done bye-bye .end