There are 3 other files named zerboo.mac in the archive. Click here to see a list.
TITLE ZERBOO -- DYNBOO extensions for calling from section zero
; COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1984, 1986.
; ALL RIGHTS RESERVED.
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND
; COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
; THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR
; ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
; AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE
; SOFTWARE IS HEREBY TRANSFERRED.
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT
; NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL
; EQUIPMENT CORPORATION.
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF
; ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
SEARCH DDBSYM, MONSYM, MACSYM
SUBTTL Edit History
; Version 1.0
;.EDIT 1 Put in section-zero call support
;.EDIT 2 Put in recursive call from section zero
;.EDIT 6 DY$ZMD shouldn't trash T1
; Version 1.1
;.EDIT 50 Formally go to version 1.1, update copyright, insert V1.1
; development changes (formally V2)
;.EDIT 51 Add GLOBbing in build procedure, make DY$CBK work from JCK.
;.EDIT 52 Fix handling of stack pointer in DY$ZMD/DY$ZMU (routines with
; stack args removed in the routine confused it)
;.EDIT 53 Add some automatic initialization for programs calling from 0.
; When attempting to call a dynamic library from section zero, two things
; must be done:
; 1. Section zero must be mapped to a nonzero section, and PC moved
; into the new section.
; 2. The stack pointer must be made global.
; These things must be done without destroying the users data in ACs or
; on the stack, so that the interface to the subroutine is not restricted.
; The sequence selected to perform this is as follows:
; The libZER file will look like a libJCK file (q.v.) except that the
; code sequence at each entry name will be as follows:
;RT1: ;Stack level on entry will be called "SP0"
; CALL DY$ZMU ;Map up to non-zero section and change stack
; ;It also stores the user return into .ZYURA
; ;and removes that word from the stack
; ;Stack returned at SP0-1
; CALL @TV+n ;Now go to the proper routine as per libJCK
; ;Stack level now SP0-1
; CALL DY$ZMD ;Map back down
; ;Stack level SP0
; RET DY.ZMV ;Return to user location
; ;(The Y field is info used in DY$CBK
; ;and probably elsewhere to find things
; ;in ZERBOO from a library)
; The section that section 0 is mapped into (if necessary) is specified
; by DY.ZMS. The content of this location is initially 1. Note that this
; should be the first non-zero section allocated, since this happens on the
; first call to the RTL.
; When section zero is actually mapped somewhere, the somewhere is recorded
DY.SEC:: 0 ;Section 0 mapped to this section number
; Pointer to special stack for recursive calls from section zero
DY.ZBL:: IFIW DY.BLK-1
; Stack of ZY blocks
DY.BLK:: BLOCK 10*.ZYLEN
; Vector of addresses in ZERBOO, for use from libraries (it's found by
; looking at the Y field of the RET instruction after the DY$ZMD call)
DEFINE ZVENT (OFFSET,CONTENTS) <
IFN .-DY.ZMV-OFFSET, <PRINTX ZV entry OFFSET out of order
DY.ZMV:: ZVENT (.ZVCNT,.ZVLEN) ;Counted vector
ZVENT (.ZVBKR, <IFIW DY$BKR>)
ZVENT (.ZVZBL, <IFIW DY.ZBL>)
ZVENT (.ZVSEC, <IFIW DY.SEC>)
ZVENT (.ZVCS0, <IFIW DY$CS0>)
SUBTTL DY$ZMU -- Map up to non-zero section, change stack
; This routine is called from the per-routine code in a libZER interface file.
; DY.ZBL/ Address of last-used ZY block
; Stack setup:
; SP0/ User call retadr
; (P)/ retadr
ADJSP P, 6 ;Stack at SP0+7
DMOVEM T0, -5(P)
DMOVEM T2, -3(P)
DMOVEM T4, -1(P)
MOVX T5, .ZYLEN
ADDB T5, DY.ZBL ;Push onto ZY stack
SETZB T0, .ZYRTZ(T5) ;Assume we're in a non-zero section
SETZ T3, ; Assume we won't do SMAP%
XHLLI T0, 1000 ;Find out
JUMPN T0, ZMUNOZ ;Jump if assumption was true
; We are in section zero. Remember this, choose a section, and map up.
SKIPE DY.SEC ;Skip if no section allocated
; Map section via indirect pointer to section 0
MOVX T1, <.FHSLF,,0>
MOVE T2, DY.ZMS ;Section we've been asked to map to
MOVEM T2, DY.SEC ;Record section we mapped to
HRLI T2, .FHSLF
MOVX T3, <SM%IND!SM%RD!SM%WR!SM%EX!1> ;All access, indirect
ERCAL DY$FJE## ;This is provided in DY$BOO
SETO T3, ; Flag that we did SMAP%
; Move PC into the new section
ZMUGOS: SETZ T1,
HRL T2, DY.SEC
HRRI T2, ZMUNOZ ;Address to jump to
; We're in a non-zero section. Worry about the stack now.
ZMUNOZ: MOVE T1, P ;Copy of P (at SP0+7)
;  ADJSP T1, -3 ;Adjust to SP0+4 for DY$ZMD
MOVEM T1, .ZYSP(T5) ; Save LH/RH relationship of SP
SKIPG T1 ;Skip if already global
XHLLI P, 1000 ;Make global current section if necessary
; Modify retadr to return into non-zero section
XHLLI T1, 1000 ;Get current section number
HLLM T1, -6(P) ;Put over flags in saved PC word
; Put away the user retadr
MOVE T1, -7(P) ;Get user retadr
MOVEM T1, .ZYURA(T5) ;Store for use after call
; If we were actually called from zero,
; make sure RTL is initialized, then store dy.sec (this section) into
; dy.zmp (galactic from rtl) so dy$cbk can tell what section represents
; a call from section zero.
JUMPE T3, ZMURST ; Jump if we didn't do SMAP%
; On first call from zero, do special initializations. This must happen
; before anything that could cause an nxp from a non-zero section (such
; as master-initializing the RTL, which will happen when the call in the
; next chunk is executed).
; First special initialization: if interrupt tables exist in section zero,
; turn off .ICNXP (page create) and .ICIRD (illegal read) interrupts.
ADJSP P, 3 ; Allocate return value block
MOVX T1, .FHSLF ;
XMOVEI T2, -2(P) ;
MOVX T3, 3 ; Block length
MOVEM T3, -2(P) ;
ERJMP ZMUDIC ;
HLRZ T1, -1(P) ; Get section of level table
JUMPN T1, ZMUFIN ; Not in zero, don't disable
ZMUDIC: MOVX T1, .FHSLF ;
MOVX T2, <1B<.ICNXP>!1B<.ICIRD>> ;
ERJMP .+1 ; Ignore errors
ZMUFIN: ADJSP P, -3 ; De-allocate return value block
;  Second special initialization:
;  Store ZMS into galactic variable
CALL @RL.CTV##+.RLNUL ; CALL RL$NUL via vector
; (we are mapped up and stack is global)
MOVE T1, DY.SEC ; Get section zero was mapped to
MOVEM T1, @DY.ZMP## ; Store where RTL can get it
; Restore our saved registers
ZMURST: DMOVE T2, -3(P) ; Add label
DMOVE T0, -5(P)
MOVE T5, -6(P) ;Get retadr
MOVEM T5, -7(P) ;Store over user retadr
DMOVE T4, -1(P) ;Restore T4, T5
ADJSP P, -7 ;Adjust to SP0
RET ;Stack at SP0-1
SUBTTL DY$ZMD -- Return to section and stack mode where we started
; Using the saved information in the ZY block pointed at by DY.ZBL
; DY.ZBL/ Address of ZY block for our use
; Stack setup:
; P/ retadr (SP0)
; NOTE: Because this knows stack layout in detail, it must not be called
; with a CALRET or equivalent!!
ADJSP P, 4 ;Stack at SP0+4
DMOVEM T1, -3(P) ;Save T1, T2
DMOVEM T3, -1(P) ;Save T3, T4
XMOVEI T4, @DY.ZBL ;Get address of ZY block
;  MOVE P, .ZYSP(T4) ;Restore SP (particularly LH of local one,
;  ;otherwise this should cause no change)
SKIPL .ZYSP(T4) ; Skip if was local
JRST ZMDSPG ; Was global, leave alone
HLRE T1, .ZYSP(T4) ; Get saved LH of SP as word quantity
HRRZ T2, .ZYSP(T4) ; Get saved RH of SP
SUB T1, T2 ; Saved LH - saved RH
HRRZ T2, P ; Current RH
ADD T1, T2 ; Saved LH + current RH - saved RH
HRL P, T1 ; becomes new RH
ZMDSPG: ; Stack pointer good
; Return to section zero, if we came from there originally (in DY$ZMU).
SKIPN .ZYRTZ(T4) ;Skip if we are to Return To section Zero
JRST ZMDSOK ;Already in right section
SETZB T1, T2 ;Section to return to is zero, if anything
HRRI T2, ZMDSOK
HLLM T1, -4(P) ;Zero LH of return address (which contains
;section we mapped in to)
XJRSTF T1 ;Return to our section zero
; Now we are in the right section, and stack is ok. Clean up.
ZMDSOK: DMOVE T1, -3(P) ;Restore T1, T2
MOVE T3, -4(P) ; Get retadr
MOVEM T3, -3(P) ;
MOVE T3, .ZYURA(T4) ;
MOVEM T3, -4(P) ;
MOVX T3, -.ZYLEN ;
ADDM T3, DY.ZBL ;
DMOVE T3, -1(P) ; Restore T3, T4
ADJSP P, -3 ;SP0+1
SUBTTL DY$BKR -- Return from callback routine
; When a routine in zero must be called from a non-zero section (such as
; an error handling routine being called by a dynamic library), assistance
; is needed on the call and the return. This routine provides the assistance
; on the return.
; DY.ZBL/ Address of one-word return address
ADJSP P, 3 ;Make work space
DMOVEM T1, -1(P)
XMOVEI T1, 0 ;Are we in Zero?
JUMPN T1, BKRNOZ ;No
; We are running in section zero. Section zero is already mapped into some
; non-zero section (or we wouldn't have reached a dynamic library, and thus
; could never have ended up here during a callback); jump into that section.
; T1 is zero
HRL T2, DY.SEC
HRRI T2, BKRNOZ
HRL P, DY.SEC ;Global stack
XJRSTF T1 ;Go up to our tame non-zero section
; We are running in a non-zero section.
BKRNOZ: MOVE T1, @DY.ZBL ;Get our true return address
MOVEM T1, -2(P) ;Put it in first of three words reserved
DMOVE T1, -1(P) ;Restore two registers saved
ADJSP P, -2 ;Return address now on top
SOS DY.ZBL ;Pop from other stack
RET ;Clean up and return to non-zero section
SUBTTL DY$CS0 -- Call into section zero
; This routine is called with a stack looking like this:
; 0,,address of routine we will call
; P/--> New stack pointer to install in DY$CS0
; There may be args in any register, or at any previous point on the stack.
; Your mission, should you decide to accept it, is to get to the routine
; specified in section zero (we're in ZMS on entry), with the stack pointer
; that's on top of the stack (and unfortunately POP P, P has "indeterminate"
; results according to the hardware reference manual; this seems to mean that
; the value popped is thrown into the bit bucket on a KL with mocrocode 550),
; and get to the routine without trashing any registers and with as little
; delay as possible. If you or any of your IFIW's are caught or killed, the
; support group will disavow any knowledge of your actions. Good luck, sucker.
EXCH T1, 0(P) ;Get stack pointer we wish to install
MOVE P, T1 ;Install it (stack points to same place,
;but is now local instead of ZMS-global)
POP P, T1 ;Restore T1
RET ;Go to routine in section zero