.title GET3_MAC .sbttl Module Header ;++ ; MACRO Program Name: GET3_MAC.MAR ; ; Usage: Invoked as a function from GET3.C ; ; Purpose: To get three longwords from the target and return to the caller ; ; Method: Goes into kernal mode, builds an ACB from nonpaged pool, queues ; a special kernal mode AST to the target process so that the target ; process can copy the data the acb extension. Then the ACB is turned ; around and the caller is issued a special kernal mode AST with the ; data. ; ; This code runs in kernal mode at IPL$_ASTDEL and IPL$_SYNCH. While ; this code is running at elevated IPL, comments will start with two ; semicolons rather than one for IPL 0. ; ; ; Requirements: this is highly privileged code ; ; Inputs: ; ; 4(ap) target process id ; 8(ap) starting address to copy from ; 12(ap) receiving address for target's 1st value ; 16(ap) blah blah blah 2nd value ; 20(ap) blah blah blah 3rd value ; 24(ap) address for a status value ; ; Output ; ;-- The requested info is written to 12,16,&20(ap) .page .sbttl equates and library calls .library /sys$library:lib.mlb/ ;+ ; equates ;- ;offsets from (AP) pid = 4 ;offset to target bit value start = 8 ;offset of start address value1 = 12 ;offset to value 1 value2 = 16 ;offset to value 2 value3 = 20 ;offset to value 3 status = 24 ;offset to status address ;+ ; externally defined symbols are contained in ;- $ACBDEF $DYNDEF $IPLDEF $PCBDEF $PRIDEF .page .psect Data .sbttl Data area ;+ ; PID storage ;- MY_IPID: .long 0 ; storage for callers IPID. HIS_IPID: .long 0 ; storage for targets IPID. ;+ ; Kernal mode error messages and handler data ;- KERNAL_ERROR: .ascid /Kernal mode code error, process will be vaporized./ KERNAL_ERROR_2: .ascid /Hopefully, just your process went and not the system./ FAOCTL: .ascid /Croaked at: !XL, Accessing Loc: !XL/ ULOGY: .ascid / / DEADPC: .long 0 BADADD: .long 0 ;+ ; addresses of allocated non-paged pool. ;- POOL1_ADDR: .long 0 POOL1_SIZE: .long 0 POOL2_ADDR: .long 0 POOL2_SIZE: .long 0 ;+ ; address array for the LCKPAG service ;- RANGE_LO: .long 0 RANGE_HI: .long 0 ;- ; stored arguments ;- VAL1: .long 0 VAL2: .long 0 VAL3: .long 0 STAT: .long 0 .page .psect kernal_handler .sbttl Kernal mode exception handler .entry handler, ^M<> ;+ ; Prints out the offending PC and memory location causing the exception. ; The only one I'm interested in is access violations. If the exception ; was NOT an accvio, I'll just die on the spot. First drop IPL to 0 ; (it cant hurt if already there), just in case I'm at elevated IPL. ;- mtpr #0, #18 ; lower IPL just in case. pushaq KERNAL_ERROR ; Embarrass user right away. calls #1, g^lib$put_output movl 4(ap), r11 ; get address of signal array. cmpl 4(r11), #SS$_ACCVIO ; Trouble if not ACCVIO beql 1000$ ; branch if IS ACCVIO $exit_s ; otherwise die (exit VMS). 1000$: movl 12(r11), BADADD ; get offending address movl 16(r11), DEADPC ; and Program Counter $fao_s ctrstr = faoctl, - ; Format a pretty message for outbuf = ulogy, - ; the user containing p1 = DEADPC, - ; offending PC ...and... p2 = BADADD ; offending address pushaq ulogy ; print the pretty message calls #1, g^lib$put_output ; on the screen pushaq KERNAL_ERROR_2 ; this other message is just calls #1, g^lib$put_output ; so the terminal server doesn't ; take over too quick and ; suppress the PC/Address ; message. $exit_s .page .sbttl address value getter, description .psect Get_data ;+ ; The ACB initially looks like: ; ; +---------------------------+ ; | FORWARD LINK (UNUSED) | ; +---------------------------+ ; | BACKWARD LINK(UNUSED) | ; +---------------------------+ ; | MODE | TYPE | SIZE | ; +---------------------------+ ; | TARGET IPID | ; +---------------------------+ ; | AST ADDR (UNUSED) | ; +---------------------------+ ; | ASTPRM (UNUSED) | ; +---------------------------+ ; | KERNAL AST ADDRESS | ; +---------------------------+ -------- Extensions are below this line ;+4 | ADDR OF POOLED AST CODE | (which moves target data to pool) ; +---------------------------+ ;+8 | STARTING ADDRESS | ; +---------------------------+ ;+12 | CALLERS IPID | (doubles as a status code on bounceback) ; +---------------------------+ ;+16 | VALUE1 | ; +---------------------------+ ;+20 | VALUE2 | ; +---------------------------+ ;+24 | VALUE3 | ; +---------------------------+ ;+28 | RETURN AST ADDRESS | ; +---------------------------+ ;- .page .sbttl address value getter, code .entry get3, ^m ; movl value1(ap), val1 ; copy arguments movl value2(ap), val2 movl value3(ap), val3 movl status(ap), stat moval 100$, RANGE_LO ; lock whole routine in memory moval END_OF_PROGRAM, RANGE_HI ; ... $lckpag_s - inadr = RANGE_LO ; call service blbc r0, 1$ ; branch if error $cmkrnl_s - ; get into kernel mode routin = 100$, - arglst = (ap) 1$: ret ; return to caller ;+ ; set up the exception handler, get the callers IPID and the targets IPID. ;- 100$:: .word 0 ; null entry mask. moval handler, (fp) ; exception handler. movl PCB$L_PID(R4), MY_IPID ; get callers Internal PID. movl PID(ap), R0 ; get targets Internal PID. jsb g^exe$epid_to_ipid movl R0, HIS_IPID ; and save it. cmpw HIS_IPID, g^sch$gl_swppid ; NULL or SWAPPER process ? bgtru 103$ ; nope, okay. movl #ss$_nonexpr, r0 ; NULL or SWAPPER illegal ret ;+ ; allocate pool for the extended ACB ;- 103$: movl #ACB$K_LENGTH+24, R1 ; # bytes to alloc for ACB LOCK QUEUEAST ;; block ASTs (prevent proc del) jsb g^exe$alononpaged ;; go get the pool blbs r0, 105$ ;; branch if successfull UNLOCK QUEUEAST ; lower ipl to normal ret ; and RETurn (status in R0) ;+ ; save pool size and address then fill in the ACB, everything but the ; address of the code to run. I'll fill that in when I allocate the ; pool for it. ;- 105$: movl R1, POOL1_SIZE ;; save size of this piece movl R2, POOL1_ADDR ;; save addr of this piece clrq (R2) ;; clear the Flink & Blink movw R1, ACB$W_SIZE(R2) ;; fill in size of this chunk movb #DYN$C_ACB, ACB$B_TYPE(R2) ;; and type, which is ACB bisb2 #ACB$M_KAST, ACB$B_RMOD(R2) ;; set Special Kernal AST bit movl HIS_IPID, ACB$L_PID(R2) ;; point AST at target process clro ACB$L_KAST+4(R2) ;; clear 4 longword extension clrq ACB$L_KAST+16(R2) ;; clear last 2 longwords ;+ ; allocate enough pool to hold the SK-AST routine. If an error occurs ; deallocate the ACB already allocated ;- movl #AST_CODE_SIZE+12, R1 ;; adding 12 account for header jsb g^exe$alononpaged ;; go get the pool blbs R0, 110$ ;; branch if successfull pushr #^m ;; save status code on stack movl POOL1_ADDR, R0 ;; get ACB address jsb g^exe$deanonpaged ;; deallocate the ACB UNLOCK QUEUEAST ; bring ipl back to normal popr #^m ; get status code off stack ret ; RETurn to caller (w/status) ;+ ; fill in enough of the "code pool" header to deallocate it. ;- 110$: movl R1, POOL2_SIZE ;; save size of this chunk movl R2, POOL2_ADDR ;; save address of this chunk movl POOL1_ADDR, R5 ;; get ACB address back movl R2, ACB$L_KAST+4(R5) ;; put POOL2 address in ACB clrq (R2)+ ;; clear FLINK & BLINK movw R1, (R2)+ ;; put in size of POOL2 movw #0, (R2)+ ;; clear "type" and "spare" byte pushr #^m ;; protect registers from MOVC3 movc3 #AST_CODE_SIZE, - ;; move this many bytes AST_CODE_ADDR, - ;; from here (start of AST code) (R2) ;; to here (12 bytes into POOL2) popr #^m ;; restore protected registers addl3 #12, ACB$L_KAST+4(R5), - ;; put addr of code into ACB ACB$L_KAST(R5) ;; adding 12 accounts for header movl START(AP), ACB$L_KAST+8(R5) ;; put starting addr in ACB movl MY_IPID, ACB$L_KAST+12(R5) ;; put callers IPID in ACB moval RET_AST_CODE, ACB$L_KAST+28(R5) ;; put in return AST address LOCK SCHED ;; synch with system data str's movzwl ACB$L_PID(R5), R4 ;; get target IPID movl G^SCH$GL_PCBVEC, R1 ;; Get PCB listhead movl (R1)[R4], R4 ;; get this IPID's PCB address cmpl PCB$L_PID(R4),ACB$L_PID(R5) ;; are the IPID's still equal? bneq 125$ ;; branch if not bbs #PCB$V_DELPEN, - ;; is the delete pending bit PCB$L_STS(R4), - ;; set (proc being deleted) ? 125$ ;; branch if so movl #PRI$_TICOM, R2 ;; bump up priority jsb g^sch$qast ;; queue AST to process UNLOCK SCHED ;; lower IPL to ASTDEL UNLOCK QUEUEAST ; lower IPL to 0 movl #SS$_NORMAL, R0 ; A-OK status code. ret ; RETurn to caller ;+ ; We should've already RETurned to the caller. If we end up at 125$ ; it means the target process was being (or had been) deleted. ;- 125$: UNLOCK SCHED ;; lower ipl to ASTDEL movl POOL2_ADDR, R0 ;; give pool back to VMS jsb g^exe$deanonpaged movl POOL1_ADDR, R0 ;; ditto jsb g^exe$deanonpaged UNLOCK QUEUEAST ; lower ipl to 0 movl #SS$_NONEXPR, R0 ; non-existant process ret ; return error .page .psect ast_request, page ;+ ; Here are the AST routines, the first, AST_CODE_ADDR is the one ; that gets executed in the context of the target process. The ; second is RET_AST_CODE which is triggered by the first and is ; executed in the context of the calling process. ; ; ACB address is in R5 Thanks to ASTDEL ; PCB address is in R4 Thanks to ASTDEL ; ; This routine copies the address value to non-paged pool, turns ; the ACB around and fires it at the calling process. ;- AST_CODE_ADDR: ; movl ACB$L_KAST+12(R5), ACB$L_PID(R5);; turn ACB around movl ACB$L_KAST+28(R5),ACB$L_KAST(R5);; point at new code bisb2 #ACB$M_KAST, ACB$B_RMOD(R5) ;; set Special Kernal AST bit movl #PRI$_TICOM, R2 ;; bump up priority movl ACB$L_KAST+8(R5), R0 ;; get starting address ifnord #12, (r0), 10$ ;; branch if can't get data movl (R0)+, ACB$L_KAST+16(R5) ;; get 1st value movl (R0)+, ACB$L_KAST+20(R5) ;; get 2nd value movl (R0)+, ACB$L_KAST+24(R5) ;; get 3rd value movl #ss$_normal, ACB$L_KAST+12(R5) ;; set a good status brb 20$ ;; jump around failure stuff 10$: movl #ss$_badparam,ACB$L_KAST+12(R5) ;; set a bad status 20$: clrq (R5) ;; clear FLINK & BLINK LOCK SCHED ;; Get up to SYNCH jsb g^sch$qast ;; queue the ast UNLOCK SCHED ; normal ipl rsb ; get out AST_CODE_SIZE = . - AST_CODE_ADDR ; .page .psect ast_reply, page ;+ ; This is the return AST service routine, it moves the data from ; the ACB to the user specified buffer, de-allocates the pool ; and turns on the event flag that the mainline is waiting for. ;- RET_AST_CODE: ; setipl #0 ; lower ipl immediately cmpl ACB$L_KAST+12(R5), #ss$_normal ; everything okay over there? beql 10$ ; yep, continue movl ACB$L_KAST+12(R5), @status(ap) ; move the bad status in brb 20$ 10$: movl ACB$L_KAST+16(R5), @val1 ; move in value #1 movl ACB$L_KAST+20(R5), @val2 ; and #2 movl ACB$L_KAST+24(R5), @val3 ; and #3 movl ACB$L_KAST+12(R5), @stat ; don't forget the status 20$: movl ACB$L_KAST+4(R5), R0 ; get ACB addr jsb g^exe$deanonpaged ; free up the ACB $setef_s efn=#0 ; set event flag rsb ; return from AST interrupt ;+ ; end of program ;- END_OF_PROGRAM: .END