



		    fim.alm                         11/11/89  1139.5rew 11/11/89  0800.0      409428



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Bull Inc., 1987                *
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1984 *
" *                                                         *
" * Copyright (c) 1972 by Massachusetts Institute of        *
" * Technology and Honeywell Information Systems, Inc.      *
" *                                                         *
" ***********************************************************

" HISTORY COMMENTS:
"  1) change(85-11-27,Herbst), approve(87-07-20,MCR7697),
"     audit(87-07-20,GDixon), install(87-08-04,MR12.1-1055):
"     Added system_message_ IPS signal.
"                                                      END HISTORY COMMENTS


"
" FIM - Multics Fault Intercept Module.
"
"	Modification record: (Date and Reason)
"	85-03-20 by E.D. Schroth (UNCA) to clear exp under/overflow
"		indicators when restarting
"	84-12-03 by EJ Sharpe for new security auditing
"         08/22/84 by R. Michael Tague: Removed dm_shutdown_warning_ and
"	    dm_user_shutdown_ from table of signals.  Added
"	    system_shutdown_scheduled_ and dm_shutdown_scheduled_.
"	07/16/84 by R. Michael Tague: Added dm_shutdown_warning_ and
"		  dm_user_shutdown_ signals to the table of signals.
"	December 1983 by Keith Loepere for hardcore breakpoint support
"	831206 by E. N. Kittlitz for hex overflow support
"	10 October 1983 by R. Coppola to meter faults and cache errors
"	on a per-cpu basis.
"	19 September 1983 by E. N. Kittlitz to set rfi+if for all overflows
"	August 1983 by Keith Loepere for minor fix to null pointer fault
"	13 October 1982 (Wednesday, this month) by E. N. Kittlitz for instruction size
"	06 October 1982 by BIM to check for signal_entry fault
"	in fim, running fim in collection 1.
"	24 March 1983 by J. A. Bush for 16/32K cache parity data capture
"	6 April 1983 by E. N. Kittlitz DRL in ring 0 causes crash.
"	sometime by BIM for bootload multics.
"	17 July 1981 by M. Weaver for undefined_pointer
"	04 June 81 by J. A. Bush to fix some unreported bugs
"	3 April 81 by Benson I. Margulies for null_pointer
"	17 Jan 81 by J. Bongiovanni for fault_counters
"	27 August 80 by J. A. Bush for the DPS8/70M
"	25 march 80 by J. A. Bush to fix negative exp. overflow bug
"	15 Jan 80 by J. A. Bush for cache parity error data capture
"	24 July 79 by J. A. Bush for new signal_entry and to merge fim_table  back in.
"	1 Feb 79 by D. Spector for new scs format for 8-cpu cioc
"	2/8/76 by Noel I. Morris for new reconfig
"	10/14/75 by R. Bratt for prelinking
"	6/20/75 by S.Webber for static handlers
"	3/75 by S. Webber for new restarting conventions and returning
"		history registers to users.
"	5/29/74 by M. Weaver to special case out of bounds on stack
"	11/1/73 by Steve Webber to allow truncation (stringsize) faults to be restarted
"	10/15/73 by Steve Webber to correct some illegal procedure "fanout" mapping problems.
"	07/21/71 by Richard H. Gumpertz to use prds_link to get prds segment number
"	5/30/70		- Noel I. Morris

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
" FIM is transferred to as the result of a fault. The control
" unit data has been stored either in pds$fim_data or pds$signal_data.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


	name	fim
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>


" 

	link	prds_link,prds$+0



	bool	lprp_insts,760000
	bool	minus_128,400000
	bool	dp_opcode,2000
	bool	inst_bit27_on,400
	bool	op_code_mask,777400
	bool	fstr_inst,470000
	bool	dfstr_inst,472000
	bool	cu_hreg,40
	bool	apu_hreg,140
	bool	access_audit_flag,400000	" indicates in fault_table that fault is auditable

	tempd	v_temp		temporary for virtual time computation
	tempd	v_delta		temporary to remember virtual_delta
	tempd	pad(2)
	temp8	mach_cond(6)	machine conditions
	temp8	history_registers(16)
	tempd	mc_ptr		pointer to machine conditions
	tempd	call_ptr		pointer to fault handling routine
	tempd	arglist(4)	argument list
	temp	fcode		fault code
	temp	temp(3)		temporary cells

" 

" ACCESS_VIOLATION_ENTRY - Handle Access Violation Faults.

	segdef	access_violation_entry

	even
access_violation_entry:
	spri	prs,*			save prs
	eppbp	prs,*			bp -> machine conditions
	sreg	bp|mc.regs		save registers
	epplp	lp,*			set lp value
	spl	bp|mc.eis_info		save eis ptrs and lengths
	tsx0	fim_util$fim_v_time_init	remember accrued virtual time
	tsx0	fim_util$check_fault  is it OK to take this fault?

	epaq	*		get our segment number
	era	bp|mc.scu.ppr.psr_word  compare against procedure segment register
	ana	scu.ppr.psr_mask,du	were we in the fim?
	tze	die_die_die_	suicide

	tra	fault_join
" 
" ONC_START_SHUT_ENTRY - entry to handle op-not-complete, startup and shutdown faults

	segdef	onc_start_shut_entry

	even
onc_start_shut_entry:
	spri	prs,*			save prs
	eppbp	prs,*			bp -> machine conditions
	sreg	bp|mc.regs		save registers
	epplp	lp,*			set lp value
	spl	bp|mc.eis_info		save eis ptrs and lengths
	lpl	eight_angry_zeros		try to condition EIS box
	tsx0	fim_util$fim_v_time_init	remember accrued virtual time

	tsx0	fim_util$check_fault  	kill Multics if not legal fault
	eppbb	pds$history_reg_data  	bb -> place to store history regs 
	tsx0	fim_util$check_mct		go save M.C.'s an hregs if required
	tsx0	fim_util$force_hist_regs	(ret ic +1) force save hregs in pds 
	tra	onc_par_join		go join common code
"
" drl_entry - entry to handle derail faults, special case of signal_entry.

	segdef	drl_entry

	even
drl_entry:
	spri	sig_prs,*		save prs
	eppbp	sig_prs,*		bp -> machine conditions
	sreg	bp|mc.regs	save registers
	epplp	lp,*		set lp value
	spl	bp|mc.eis_info	what the hell...
	ldq	bp|mc.scu.ppr.prr_word check whether running in ring-0
	canq	scu.ppr.prr_mask,du	ring number in ppr
	tnz	drl_join		not ring 0

	stz	scs$drl_message_pointer assume the worst
	lda	bp|mc.scu.ilc_word
	eppbb	0,au		offset of DRL 
	lda	bp|mc.scu.ppr.psr_word
	ana	scu.ppr.psr_mask,du
	easpbb	0,au		segno of DRL
	lda	bb|0		get the DRL instruction
	ana	=o777777,du
	tze	drl_die		no operand
	cmpa	=o777777,du
	tze	breakpoint	drl -1 => breakpoint

	eawpbb	0,au		operand of DRL instruction
	sprpbb	scs$drl_message_pointer
drl_die:	tra	fim_util$drl_fault_trouble punt ye system
"
" Handle a hardcore breakpoint - call bce

breakpoint:
	eppap	flagbox$
	lda	fgbx.breakpoint,du
	orsa	ap|fgbx.rtb

	eppap	breakpoint_page$		place so bce can find
	tsx0	fim_util$copy_mc
	scpr	bp|bkpt_page.mode_reg,06
	sdbr	bp|bkpt_page.dbr
	sbar	bp|bkpt_page.bar

	tsx0	fim_util$reset_mode_reg

	lda	1,du			make so simple bce go works
	adla	bp|mc.scu.ilc_word
	sta	bp|mc.scu.ilc_word
	lda	scu.cu.rfi,dl		refetch instruction
	sta	bp|mc.scu.cu_stat_word

	eppsb	pds$stack_0_ptr,*
	ldx7	push
	tsx0	fim_util$push_stack		prepare for pmut call

	call	pmut$bce_and_return

	eppap	flagbox$
	lca	fgbx.breakpoint,du
	sba	1,dl		make sure bit off
	ansa	ap|fgbx.rtb

	eppap	prs,*		ap -> wired-down m.c.
	mlr	(pr),(pr)
	desc9a	bp|mc.scu,8*4
	desc9a	ap|mc.scu,8*4

	sprisp	sb|stack_header.stack_end_ptr	pop frame

	eppbp	breakpoint_page$		return to break
	lpl	bp|mc.eis_info
	lreg	bp|mc.regs
	lpri	bp|mc.prs
	rcu	scu,*		return to breakpoint
"
" parity_entry - entry to handle parity faults

	segdef	parity_entry
	even
parity_entry:
	lcpr	cache_off,02		turn cache off in case this is cache parity
	spri	prs,*			save prs
	eppbp	prs,*			bp -> machine conditions
	sreg	bp|mc.regs		save registers
	epplp	lp,*			set lp value
	spl	bp|mc.eis_info		save eis ptrs and lengths
	tsx0	fim_util$fim_v_time_init	remember accrued virtual time
	eppbb	pds$history_reg_data	bb -> place to store history regs 
	tsx0	fim_util$check_mct		go save M. C.'s and hregs if required
	tsx0	fim_util$force_hist_regs	(ret ic +1) force save hregs in pds
	lda	bp|mc.fault_reg		load fault reg
	cana	12,dl			is it cache store or cache dir parity?
	tnz	csd_par			xfer if yes
	tsx0	fim_util$check_fault	no, kill Multics if parity in hardcore etc.
	tra	onc_par_join		and join common code

csd_par:	stz	pds$cpar_info		initialize cache parity info structure
	cana	4,dl			is it cache store parity?
	tnz	cstr_par			xfer if yes
	tsx0	fim_util$check_fault	no cache dir parity
	tsx0	save_cache		go save cache enable bits
	tra	onc_par_join		and join common code

cstr_par:	lda	bp|mc.scu.cpu_no_word	Get the cpu number in A
	ana	scu.cpu_no_mask,dl
	arl	scu.cpu_shift		right justify in AL
	ldx1	scs$processor_data,al	Get cache size
	anx1	7,du			in X1
	eax1	-1,1			can't have 0 size at this point
	epaq	fim_abs_seg$		get ptr to abs seg
	als	1			multiply by 2
	eax7	0,au			copy segno to x7
	eppap	fim_abs_seg$		set ap with abs_seg ptr
	eax2	15*2			set initial cu hreg index
cuhrlp:	eax5	15*2			set initial apu hreg index
	tsx0	fnd_crd			go check for cache read cycle
	tra	apuhrlp			return ic+1, cache read (L68)
	tra	dps8_hit			return ic+2, cache read (DPS8)
dec_cux:	eax2	-2,2			return ic+3, not cache read
	tmi	no_find			exit if no more cu hregs
	tra	cuhrlp			go get next cu hreg

apuhrlp:	ldaq	bb|apu_hreg,5		load next apu hreg
	cana	apuhra.fap+apuhra.fanp,dl	is this final address (fanp or fap)?
	tze	dec_apx			xfer if no, skip to next apu hreg
	qrl	apuhra.finadd_shift		right justify abs addr
	anq	=o777,dl			and out upper addr bits
	cmpq	bp|mc.fim_temp		is this the same as cu addr?
	tze	addmatch			xfer if yes
dec_apx:	eax5	-2,5			no, go to nxt apu hreg
	tmi	dec_cux			get nxt cu hreg is apu hregs exhausted
	tra	apuhrlp			get nxt apu hreg

addmatch:	lda	bb|apu_hreg+1,5		matching cu and apu address
	cana	apuhra.encache,dl		is segment encacheable?
	tze	dec_cux			xfer if no, go to nxt cu/apu match
dps8_hit:					" Enter here if dps8 cache read
	arl	12			zero out all but 24 bit address
	sta	pds$cpar_info		and save
	eax6	0,al			copy lower 256k address to x6
	anx6	c_256k_mask,1		make mod <cache size> address
	ana	c_abs_addr_mask,1		make absaddr mod <cache size>
	als	12			shift into position
	ora	sdw.valid,dl		set directed fault bit
	ldq	c_sdw_bounds,1		set up rest of sdw
	staq	dseg$,7			set sdw in dseg
	cams				"clear associative memory
	camp
	ldaq	ap|0,6			get memory contents
	staq	pds$cpar_mem_data		and save
	anx6	c_lv_st_mask,1		make address start at level 0
	eax3	-4			x3 counts levels
cparlvlp:	ldi	scu.ir.parm,dl		set parity mask
	lcpr	cache_to_reg_mode,02	set cache dump mode
	ldaq	ap|0,6			dump cache contents
	lcpr	cache_off,02		reset cache dump mode
	sti	bp|mc.fim_temp		save indicators
	eraq	pds$cpar_mem_data		exclusive or it with data in mem
	staq	pds$cpar_err_data		save it
	ldi	0,dl			reset parity mask
	lda	bp|mc.fim_temp		load indicators
	cana	scu.ir.par,dl		parity error?
	tnz	cpar_hit			xfer if yes
nxt_lvl:	adx6	c_lv_inc_tab,1		get set for nxt level
	eax3	1,3			any more levels?
	tmi	cparlvlp			yes, go to nxt level
	tra	dec_cux			no, go check previous read

cpar_hit:	ldi	scu.ir.oflm,dl		mask overflows
	lcaq	pds$cpar_err_data		get compliment of XOR data
	ldi	0,dl			reset overflow mask
	anaq	pds$cpar_err_data		and 2s compliment data with itself
	cmpaq	pds$cpar_err_data		if single bit failure, it should compare
	tnz	nxt_lvl			multiple bit failure, go try nxt level
	ldi	scu.ir.parm,dl		set parity mask
	lcpr	cache_to_reg_mode,02	set cache dump mode
	ldaq	ap|0,6			dump cache contents
	lcpr	cache_off,02		reset cache dump mode
	staq	pds$cpar_err_data		save it
	ldi	0,dl			reset parity mask
	eaa	0,6			copy level info to a
	arl	c_lv_shift,1		position per cache size
	ana	=o300,du			and out all but level
	ora	=o400000,du		set flag for data capture
	orsa	pds$cpar_info		and save
no_find:	lda	0,du
	ldq	0,du			zero out abs seg sdw
	staq	dseg$,7
	cams	4			clear assosiative memory and cache
	camp
	tsx0	save_cache		go save cache enable bits
	tsx0	fim_util$check_fault	now go check to see if fault in hardcore
	tra	onc_par_join		and go join common code
" 
" signal_entry - entry to handle faults that are directly signalable
" in the outer rings (not ring 0)

	segdef	signal_entry

	even
signal_entry:
	spri	sig_prs,*			save prs
	eppbp	sig_prs,*			bp -> machine conditions
	sreg	bp|mc.regs		save registers
	epplp	lp,*			set lp value
	spl	bp|mc.eis_info		save eis ptrs and lengths
drl_join:
	tsx0	fim_util$fim_v_time_init	remember accrued virtual time
	tsx0	fim_util$check_fault	kill Multics if not legal fault
	lda	bp|mc.scu.fault_data_word
	ana	scu.fi_num_mask,dl		get fault address
signal_it:
	sta	bp|mc.errcode		temporarily save fault code
	arl	1			divide by 2
	ldq	prds$processor_tag		get cpu num
	xec	fault_ctr_tab,ql		BB => per-cpu fault ctr array	
	aos	bb|0,al			and increment the fault ctr
	als 	1			multiply by 2
	ldaq	fault_table,al		pick up table entry
	anq	access_audit_flag,dl	do we need to audit this event?
	tze	no_sig_audit		xfer if no.
	tsx1	call_audit_for_signal	yes, go do it (will push frame)
no_sig_audit:
	tra	0,au			dispatch on entry value

call_signaller:				"most signalable faults come here directly
	eppbb	pds$history_reg_data	bb -> place to store history regs 
	tsx0	fim_util$check_mct		go save M. C.'s and hregs if required
	tsx0	fim_util$hist_regs		(ret ic +1) save hregs in pds
	tsx0	fim_util$reset_mode_reg  	(ret ic +2) turn them back on now
	lda	bp|mc.errcode		get fault code for retrieving name
	arl	1			divide by 2
	sta	bp|mc.fim_temp		save the sct index for signal_
	als	1			multiply by 2
	stz	bp|mc.errcode		initialize error code
	lda	fault_table+1,al		pick up second word of fault table entry
	eppbb	0,au			get pointer to name from its left half word
	eppab	pds$condition_name		get pointer to place to store name
	ldq	bb|0			get first word of string for ACC size
	qrl	27			right justify size of string
	adlq	1,dl			add 1 for count character
	mlr	(pr,rl),(pr),fill(0)
	desc9a	bb|0,ql
	desc9a	ab|0,32
	eppsb	pds$stack_0_ptr,*		set SB to the ring 0 stack
	tra	signaller$signaller		now give control to the signaller
"
call_audit_for_signal:		" security auditing for signal_entry
	ldq	audit_flags.faults,dl get process's audit flags
	canq	pds$audit_flags	Check appropriate audit flag
	tze	0,1		Not auditing, go back

	eppsb	pds$stack_0_ptr,*	make FIM's stack frame on the ring 0 stack
	ldx7	push		..
	tsx0	fim_util$push_stack	..
	eppap	mach_cond		ap -> place for machine conditions
	tsx0	fim_util$copy_mc	copy machine conditions into stack frame
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->
	spribp	mc_ptr		set mc_ptr in stack frame
	eppap	mc_ptr		Get machine conditions pointer
	spriap	arglist+2		Stuff it in arg list
	fld	=1b24,dl		One argument
	ora	=o4,dl		Make arglist header
	staq	arglist		Stuff it where it belongs
	call	access_audit_log_fault_$log_fault(arglist)	Call fault entry in auditor
	eppap	pds$signal_data	copy M.C.s back to signal data
	tsx0	fim_util$copy_mc
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	sprisp	sb|stack_header.stack_end_ptr reset stack end pointer (and pop frame)
	lda	bp|mc.errcode	restore the fault code from the MC
	lda	fault_table,al	and pick up table entry
	tra	0,1		and return
" 
" PRIMARY_FAULT_ENTRY - Most faults arrive at this entry.

	segdef	primary_fault_entry

	even
primary_fault_entry:
	spri	prs,*			save prs
	eppbp	prs,*			bp -> machine conditions
	sreg	bp|mc.regs		save registers
	epplp	lp,*			set lp value
	spl	bp|mc.eis_info		save eis ptrs and lengths
	tsx0	fim_util$fim_v_time_init	remember accrued virtual time
	tsx0	fim_util$check_fault	kill Multics if not legal fault
fault_join:
	eppbb	pds$history_reg_data  bb -> place to store history regs 
	tsx0	fim_util$check_mct	go save M.C.'s an hregs if required
	tsx0	fim_util$hist_regs	(ret ic +1) save hregs (if not saved by check_mct)
onc_par_join:
	tsx0	fim_util$reset_mode_reg   (ret ic +2) turn them back on now
	eppsb	pds$stack_0_ptr,*	make FIM's stack frame on the ring 0 stack
	ldx7	push		..
	tsx0	fim_util$push_stack	..
	eppap	mach_cond		ap -> place for machine conditions
	tsx0	fim_util$copy_mc	copy machine conditions into stack frame
	spribp	mc_ptr		set mc_ptr in stack frame
	ldaq	pds$fim_v_temp	save CPU time at start of fault
	staq	v_temp		..
	ldaq	pds$fim_v_delta	save virtual delta at start of fault
	staq	v_delta		..
	szn	pds$hregs_saved  	do we want to copy hregs?
	tze	no_hist
	eppap	history_registers	bb -> hregs either in mc_trace buffer or pds
	mlr	(pr),(pr)		copy hregs into stack frame
	desc9a	bb|0,128*4
	desc9a	ap|0,128*4
no_hist:	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

" Dispatch on Fault Code.

	stz	bp|mc.errcode	clear the error code
	lda	bp|mc.scu.fault_data_word get fault number
	ana	scu.fi_num_mask,dl
set_fault:
	sta	fcode		save the fault code
	arl	1		divide by 2
	ldq	prds$processor_tag	get cpu num in QL
	xec	fault_ctr_tab,ql	BB=> per-cpu fault counter
	aos	bb|0,al		increment the fault counter
	sta	bp|mc.fim_temp	save the fault code in the MC
	als	1		multiply by 2
	ldaq	fault_table,al	pick up table entry
	anq	access_audit_flag,dl	get special action code for this fault
	tze	no_pri_audit	xfer if no need to audit
	tsx1	call_audit_for_primary	we need to audit this event
no_pri_audit:
	tra	0,au		dispatch on entry value

fault_ctr_tab: 
	eppbb	wired_hardcore_data$cpu_a_flt_ctr_array
	eppbb	wired_hardcore_data$cpu_b_flt_ctr_array
	eppbb	wired_hardcore_data$cpu_c_flt_ctr_array
	eppbb	wired_hardcore_data$cpu_d_flt_ctr_array
	eppbb	wired_hardcore_data$cpu_e_flt_ctr_array
	eppbb	wired_hardcore_data$cpu_f_flt_ctr_array
	eppbb	wired_hardcore_data$cpu_g_flt_ctr_array
	eppbb	wired_hardcore_data$cpu_h_flt_ctr_array
" 

call_audit_for_primary:		" security auditing for primary_fault_entry
	ldq	audit_flags.faults,dl get process's audit flags
	canq	pds$audit_flags	Check appropriate audit flag
	tze	0,1		Not auditing, go back
	eppap	mc_ptr		Get machine conditions pointer
	spriap	arglist+2		Stuff it in arg list
	fld	=1b24,dl		One argument
	ora	=o4,dl		Make arglist header
	staq	arglist		Stuff it where it belongs
	call	access_audit_log_fault_$log_fault(arglist)  Call fault entry in auditor
	lda	fcode		Pick up the fault code again
	lda	fault_table,al	Pick up the table entry
	tra	0,1		Go back

"

"	Set up the call to the appropriate handler.
"
"	The right half of the accumulator contains an offset
"	in the fim's linkage section of the procedure to call
"	to handle the fault.
"
"	All handlers are called in the following way:
"
"	call handler (mc_ptr)
"
"	where mc_ptr points to the machine conditions, not the
"	SCU data.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


call_signaller_signal:
	arg	call_signaller
	arg	call_signal

standard.signal_check_coll:
	eax0	1
	tra	standard.check_common

standard.signaller_check_coll:
	eax0	0
standard.check_common:
	ldq	sys_info$initialization_state
	cmpq	1,dl
	tmoz	call_signaller_signal,x0*

standard:
	eppap	lp|0,al*		generate pointer to the handler
	spriap	call_ptr		save the handler pointer

	fld	=1b24,dl		set up argument list header (1 argument)
	ora	=o4,dl
	staq	arglist

	eppap	mc_ptr		set up argument list (1st arg is mc_ptr)
	spriap	arglist+2

	tra	call

" 
"	Access Violation faults
"
"	All access violation subcases are separated out
"	in the next sequence of code. Some are signalled, some are handled
"	by the system.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


access_violation:
	lda	bp|mc.scu.fault_data_word get sub-class of access violation fault
	ana	-1,du		leave only sub-class bits
	eax7	0		 Determine which is highest bit on.
acv_bit_loop:
	cana	=o400000,du	 Test bit.
	tnz	acv_bit_end

	eax7	2,7		 On to next bit.
	als	1
	tnz	acv_bit_loop	 Unless all bits off.

acv_bit_end:
	eaa	avf,7	generate simulated code word
	cmpa	oob,du	see if bound fault (if so make special checks)
	tze	check_special_oob	yes, make tests

	tra	fixindex_1	must be normal access violation of some type

check_special_oob:
	ldq	bp|mc.scu.tpr.tsr_word "fetch the TSR
	anq	scu.tpr.tsr_mask,du	leave only segment number
	eax7	null		get set for simfault
	cmpq	=o077777,du	is it a null pointer?
	tze	fixindex		yes, handle the null pointer.
	cmpq	=o077776,du	is a terminate process?
	tze	term_it		yes, go handle it
	eax7	undefp		get set for undefined_pointer
	cmpq	=o077775,du	is it an undefined pointer?
	tze	fixindex		yes, handle it
	eax7	stk_oob		get set for out_of_bounds on stack
	erq	bp|mc.prs+6*2	exclusive or  stack segno with  tsr
	anq	=o077777,du	set indicators to note any difference
	tze	fixindex		no,  call handler to extend stack
	tra	fixindex_1	not special oob, treat as real oob


fixindex:
	eaa	0,7		new index in A
fixindex_1:
	sbla	fault_table,du  get relative address
	arl	18		right-justify
	tra	set_fault		back to the dispatch table

"
"	Command faults
"
"	The command fault could be either hardware oriented, configuration
"	oriented, or an attempt to load a faulting packed pointer.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


command_fault:
	eax7	com	assume normal command fault
	ldq	bp|mc.scu.port_stat_word check illegal action
	canq	scu.ial_mask,dl
	tnz	fixindex		nonzero, treat as normal case
	ldq	bp|scu.even_inst_word check for LPRPxx instruction
	anq	=o770400,dl
	cmpq	lprp_insts,dl
	tnz	fixindex		isn't LPRPxx, treat as normal

"	It is packed pointer fault. See if system version.

	eax7	ppf	
	ldq	bp|mc.scu.ca_word	pick up faulting pointer pair
	lda	bp|mc.scu.tpr.tsr_word
	ana	scu.tpr.tsr_mask,du
	easp3	0,au		generate pointer
	eawp3	0,qu
	lda	bb|0		pick up the packed pointer
	cana	=o100000,du	check system bit
	tze	fixindex		not ON. Treat as normal packed pointer fault
	ana	=o000777,du
	cmpa	3,du
	tpl	fixindex
	als	1		multiply by 2
	eax7	sppf,au
	tra	fixindex
" 
"	Overflow faults
"
"	The overflow fault could result from one of:
"
"	fixedoverflow
"	exponent overflow
"	exponent underflow
"	stringesize (EIS truncation fault)
"
"
"	The following code looks at the indicators to see what kind
"	of overflow fault occured and to remap the fault into the
"	corresponding name.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
split_overflow:
	lda	scu.cu.rfi+scu.cu.if,dl	set rfi and if bits
	orsa	bp|mc.scu.cu_stat_word	in cu status word
	ldq	bp|mc.scu.indicators_word	get the indicators and ilc
	eax3	0			set ^hex mode
	canq	scu.ir.hex,dl
	tze	sov_binary		IR bit not set, so binary it is
	szn	pds$hfp_exponent_enabled	is per-process enablement on?
	tze	sov_binary		nope
	eax3	1			hex mode if exponent ufl/ofl
sov_binary:
	canq	scu.ir.ovfl,dl		is it "fixedoverflow"?
	tnz	ck_eis_size		yes go check for eis size.
	canq	scu.ir.eufl,dl		is it "underflow"?
	tze	ck_eovfl			no, go check for exp overflow
	eax7	eufl			yes, set exp underflow index
	tsx1	ck_str_rd			go get op_code from object seg
	tra	sig_index			return (ic+1), don't restart EIS
	tra	set_und_rfi		return (ic+2) don't increment ic
	adlq	1,du			return (ic+3) increment ic
	stq	bp|mc.scu.ilc_word		by one and restore ic word
set_und_rfi:
	stz	bp|mc.regs+4		zero out saved a
	stz	bp|mc.regs+5		and q regs
	lda	minus_128,du		and set e reg to -128
	sta	bp|mc.regs+6
	ldq	pds$exp_undfl_rest		restart fault in the fim?
	qls	0,x3			shift according to bin/hex mode
	tpl	sig_index			xfer if no, go signal fault
	ldq	prds$processor_tag		restarting so count fault here. get cpu num
	xec	fault_ctr_tab,ql		BB => per-cpu fault ctr array	
	aos	bb|(eufl-fault_table)/2	and increment the fault ctr
	lda	bp|mc.scu.indicators_word	get indicator reg
	ana	-(scu.ir.neg+scu.ir.eufl+1),dl negative and exp underflow indicators off
	ora	scu.ir.zero,dl		and set zero indicator
und_ovr_rest:
	stba	bp|mc.scu.indicators_word,14	and restore indicators
	lca	scu.ir.eufl+scu.ir.eovf+1,dl	reset exp over/under flow indicators
	ansa	bp|mc.scu.indicators_word
	tsx0	fim_util$reset_mode_reg	turn hregs back on
	sznc	pds$connect_pending		is connect pending?
	tze	no_con_pend		if not, skip next
	lxl1	prds$processor_tag		CPU tag in X1
	cioc	scs$cow_ptrs,1* 		do a connect now
	lra	=0			prevent ring alarm before cioc takes
no_con_pend:
	lreg	bp|mc.regs		restore the registers
	lpri	bp|mc.prs			and the prs
	rcu	sig_scu,*			return to faulting location

ck_eovfl:
	canq	scu.ir.eovf,dl		is it "overflow"?
	tze	ck_trunc			no, go check truncation
	eax7	eovf			yes, load table index
	tsx1	ck_str_rd			check for fstr/dfstr instr
	tra	sig_index			return (ic+1), don't restart EIS
	tra	ck_ovfl_rest		return (ic+2), don't increment ic
	adlq	1,du			return (ic+3) increment ic
	stq	bp|mc.scu.ilc_word		by one and restore ic word
ck_ovfl_rest:
	ldq	pds$exp_ovfl_rest		restart fault in fim?
	qls	0,x3			shift according to bin/hex
	tpl	sig_index			xfer if no, go signal fault
	ldq	prds$processor_tag		restarting, so count fault here. get cpu num
	xec	fault_ctr_tab,ql		BB => per-cpu fault ctr array	
	aos	bb|(eovf-fault_table)/2	and increment the fault ctr
	eax3	0,x3			re-sex mode
	tnz	hex_ovfl
	canx5	dp_opcode,du		yes, is this double precision?
	tnz	doub_prec			xfer if yes
	fld	pds$eovfl_value		no, load sp restart value
	tra	str_rest_vlu		and go store it

doub_prec:
	dfld	pds$eovfl_value		load dp restart value
str_rest_vlu:
	szn	bp|mc.regs+4		is this a negative overflow?
	tpl	no_negate			no, store value as is
	fneg	0			yes, negate the value
no_negate:
	staq	bp|mc.regs+4		and store it
	ste	bp|mc.regs+6		store exponent
	lda	scu.cu.rfi+scu.cu.if,dl	set rfi and if bits
	orsa	bp|mc.scu.cu_stat_word	in cu status word
	lda	bp|mc.scu.indicators_word	get indicator register
	ana	-(scu.ir.eovf+1),dl		turn off overflow indicator
	tra	und_ovr_rest		go restart overflow

hex_ovfl:	ldi	scu.ir.hex,dl		enable hex mode
	canx5	dp_opcode,du		yes, is this double precision?
	tnz	hex_doub_prec		xfer if yes
	fld	pds$hex_eovfl_value		no, load sp restart value
	ldi	0,dl			clear hex mode
	tra	str_rest_vlu		and go store it

hex_doub_prec:
	dfld	pds$hex_eovfl_value		load dp restart value
	ldi	0,dl			clear hex mode
	tra	str_rest_vlu

ck_eis_size:
	eax7	ovfl			set up for "fixedoverflow"
	canq	scu.ir.mif,dl		is it EIS fault?
	tnz	ck_sz_loc			xfer if yes
sig_index:
	eaa	0,7			copy  fault index to a
	sbla	fault_table,du		get relative address
	arl	18			right justify
	tra	signal_it			and go signal fault

ck_sz_loc:
	lda	bp|scu.even_inst_word	is this potenialy eis instr?
	cana	inst_bit27_on,dl		if bit 27 is not on, can't be eis inst
	tze	sig_index			no, signal fixedoverflow
	eax7	size_loc			set size fault index
	tra	sig_index			and go signal it

ck_trunc:
	canq	scu.ir.tru,dl		is it truncation?
	tze	fim_util$fault_trouble	hardware error id none of above
	eax7	trun			yes, set truncation fault index
"
"	We have a "stringsize" condition. Set up the machine
"	conditions so we can restart the instruction.
"
	szn	pds$pl1_machine		can we alter apparent machine ops?
	tze	sig_index			xfer if no, bare 6180 machine
	tsx1	get_instruction_size
	adla	bp|mc.scu.ilc_word		increment ic by eis instr size
	sta	bp|mc.scu.ilc_word		and restore ic word
	lca	scu.ir.mif+1,dl		we must turn OFF this indicator so the next
	ansa	bp|mc.scu.indicators_word  	EIS instruction will be correctly initialized
	lda	scu.cu.rfi+scu.cu.if,dl	set rfi and if bits
	orsa	bp|mc.scu.cu_stat_word	in cu status word
	tra	sig_index			go signal "stringsize"

"
"	Illegal procedure faults
"
"	There are several subcases which are distinguished
"	They are:
"		illegal op code
"		illegal address and modifier
"		other illegal procedure faults
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


illegal_procedure:

	epaq	*		get our segment number
	era	bp|mc.scu.ppr.psr_word  compare against procedure segment register
	ana	scu.ppr.psr_mask,du	were we in the fim?
	tze	die_die_die_	suicide
	lda	bp|mc.scu.fault_data_word get the fault dataister
	eax7	foc	get set for illegal op code
	cana	scu.fd.ioc,du
	tnz	sig_index		yes, use the given index

	eax7	bam	get set for bad modifier or address
	cana	scu.fd.ia_im,du
	tnz	sig_index

	eax7	ipr	get set for all other illegal procedure
	tra	sig_index
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	fnd_crd - subroutine to check for cache read cycle in current CU history reg
"	for cache parity diagnostics.
"	return is ic+1, if L68 cache read cycle,
"		ic+2, if dps8 cache read cycle (A reg contains abs addr, in upper)
"		ic+3, if not a cache read cycle
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

fnd_crd:	ldaq	bb|cu_hreg,2		load next cu hreg
	cmpx4	1,du			is this a dps8 cpu?
	tze	cu_dps8			xfer if yes, otherwise  L68
	canq	cuhra.dir,dl		is this direct cu cycle?
	tnz	2,0			xfer if yes, skip to next cu hreg
	lls	18			position addr in al
	anq	=o760000,du		mem cmd in qu
	tze	l68_rd_cmd		xfer if single precision read
	cmpq	=o40000,du		no, is it D.P read?
	tze	l68_rd_cmd		xfer if yes
	tra	2,0			not cache read, return ic+3

l68_rd_cmd:
	ana	=o777,dl			discard upper address
	sta	bp|mc.fim_temp		save address
	tra	0,0			return ic+1, L68 cache read

cu_dps8:	cana	cuhr.pia,du		dps8 pia cycle?
	tze	2,0			No, return ic+3
	cana	cuhr.internal,du		dps8 cache cycle?
	tze	2,0			No, return ic+3
	lda	bb|cu_hreg+1,2		got a hit, load abs addr in A
	tra	1,0			return ic+2, DPS8 cache read

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	save_cache - subroutine to save current state of cache memory enable bits
"	(csh1 and csh2) located in the prds$cache_luf_reg and then reset the bits
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

save_cache:
	lda	prds$cache_luf_reg		get current cache enable bits
	ana	=o600000,dl		and out all but csh1 and csh2
	als	10			position
	orsa	pds$cpar_info		and save in pds
	lda	3,dl
	ansa	prds$cache_luf_reg		turn off all cache enable bits
	tra	0,0			return to caller
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	ck_str_rd - subroutine to check if faulting instruction is a
"	FSTR or DFSTR by looking in the object segment at psr|ic.
"	entry:	tsx1	ck_str_rd
"	in regs:	QR =	ilc,indicator word from scu data
"		BP ->	machine conditions
"	out regs:	QR	is unchanged
"		x5  =	instruction op code
"	return:	ic+1 if bit 27 is on (EIS instruction)
"		ic+2 if instruction is fstr or dfstr instruction
"		ic+3 if any other instruction
"
"	NOTE:
"	Theory of touching the text segment, as of 82-10-26.
"	Yes, we might take a page or segment fault on the load
"	of the instruction word.  However, it is VERY unlikely, given
"	selection algorithms for evicting a page/segment.
"	Further, the SDW and PTW are almost certainly in our AM, and
"	we haven't been listening to any connects to get them out.
"	If we take a seg_fault, we'll be using fim_data for machine
"	conditions, and the only fim routines that call this routine
"	are supposed to have come in using signal_data/signal_entry.
"	Thus, we don't have to worry about our data getting clobbered.
"	If we end up taking a seg-fault error (seg deleted), or
"	a page-fault error, we're just going to signal that error
"	anyhow. For anything except the original fault being in
"	ring zero, this means crawlout.  
"	For ring zero, we would conceivably have to worry about
"	someone having a handler for such an error and actually
"	wanting to restart the original fault. "It'll never happen."
"
"	All this makes us think that it isn't worth the expense
"	of moving the machine conditions to a stack frame before
"	touching the text instruction.  
"	
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

ck_str_rd:
	lda	bp|mc.scu.ppr.psr_word
	ana	scu.ppr.psr_mask,du
	eppab	0,qu			set word offset, pr.ringno=0
	easpab	0,au			get segno from psr
	lxl5	ab|0			load instruction op code in x5
	anx5	op_code_mask,du		just look at op code
	canx5	inst_bit27_on,du		is this an EIS instruction?
	tnz	0,1			yes, return ic+1
	cmpx5	fstr_inst,du		fstr instruction?
	tze	1,1			return ic+2 if yes
	cmpx5	dfstr_inst,du		no, dfstr instruction?
	tze	1,1			return ic+2 if yes
	tra	2,1			no, return ic+3

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	get_instruction_size - subroutine to determine the size of an instruction
"	by looking in the object segment at psr|ic.
"	entry:	tsx1	get_instruction_size
"	in regs:	QR =	ilc,indicator word from scu data
"		BP ->	machine conditions
"	out regs:	QR	is unchanged
"		X5  =	instruction op code
"		AU =	instruction size 
"
"	See the NOTE in check_str_rd.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

get_instruction_size:
	lda	bp|mc.scu.ppr.psr_word
	ana	scu.ppr.psr_mask,du
	eppab	0,qu			get word offset from ilc, set PRab.ring = 0
	easpab	0,au			get segno from psr
	lxl5	ab|0			load instruction op code in x5
	anx5	op_code_mask,du		just look at op code
	lda	1,dl			default to 1 word
	canx5	inst_bit27_on,du		is this an EIS instruction?
	tze	0,1			no, return
	eaa	gis_table			table pointer

gis_loop:	cmpx5	0,au			gone far enough down the table?
	tnc	gis_found			got it
	eaa	1,au			get next entry
	tra	gis_loop

gis_found:
	lda	0,au			return the size
	als	18	
	tra	0,1


gis_table:
	vfd	9o/057,1/1,8/0,18/4		mve,mvne
	vfd	9o/117,1/1,8/0,18/3		csl,csr,sztl,sztr,cmpb,mlr,mrl,cmpc
	vfd	9o/127,1/1,8/0,18/4		scd,scdr,scm,scmr
	vfd	9o/157,1/1,8/0,18/1		sptr
	vfd	9o/167,1/1,8/0,18/4		mvt,tct,tctr
	vfd	9o/177,1/1,8/0,18/1		lptr
	vfd	9o/217,1/1,8/0,18/3		ad2d,sb2d,mp2d,dv2d
	vfd	9o/227,1/1,8/0,18/4		ad3d,sb3d,mp3d,dv3d
	vfd	9o/277,1/1,8/0,18/1		lsdr,sbpb0-3,ssdr,lptp
	vfd	9o/307,1/1,8/0,18/3		mvn,btd,cmpn,dtb
	vfd	9o/777,9o/777,18/1		easpN,epbpN,sareg,spl,lareg,
					" and all the others...

" 
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

" Make call to fault handler.

call:
	call	call_ptr,*(arglist)	make the call


" Test for error .

	eppbp	mach_cond		bp -> machine conditions
	szn	bp|mc.errcode	test for error
	tnz	call_signal	..

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

	eppap	prs,*		ap -> wired-down m.c.
	mlr	(pr),(pr)
	desc9a	bp|mc.scu,8*4
	desc9a	ap|mc.scu,8*4

	ldaq	v_temp		restore virtual time parameters
	staq	pds$fim_v_temp	..
	ldaq	v_delta		..
	staq	pds$fim_v_delta	..

	lda	fcode		get fault code again
	ldaq	fault_table,al  load table entry

	sprisp	sb|stack_header.stack_end_ptr reset stack end pointer

	sznc	pds$connect_pending	must we do connect?
	tze	no_connect	if not, skip next
	lxl1	prds$processor_tag	CPU tag in X1
	cioc	scs$cow_ptrs,1* 	do a connect now
	lra	=0		prevent ring alarm before connect takes
no_connect:

	canq	=o1,dl		suspend virtual time?
	tze	no_v_time_meter	if not, don't meter
	odd
	tsx0	fim_util$fim_v_time_calc  compute virtual delta
no_v_time_meter:

	lpl	bp|mc.eis_info		save eis ptrs and lengths
	lreg	bp|mc.regs	restore the registers
	lpri	bp|mc.prs		and the prs
	rcu	scu,*		return to faulting location
" 
"	Come here when time to signal the event.


call_signal:
	lda	bp|mc.fim_temp	resignal?
	cana	=o400000,dl	..
	tze	call_signal.1	no.

	als	1		get new fault code
	stca	fcode,07

call_signal.1:
	lxl7	fcode		get fault code for retrieving name
	lda	fault_table+1,7  pick up second word of fault table entry
	eppbb	0,au		get pointer to name from its left half word
	eppab	pds$condition_name	get pointer to place to store name
	ldq	bb|0		get first word of string for ACC size
	qrl	27		right justify size of string
	adlq	1,dl		add 1 for count character
	mlr	(pr,rl),(pr),fill(0)
	desc9a	bb|0,ql
	desc9a	ab|0,32

	eppap	pds$signal_data
	tsx0	fim_util$copy_mc
	eppsb	pds$stack_0_ptr,*	get a pointer to the base of the ring 0 stack
	szn	pds$hregs_saved
	tze	signaller$signaller

	mlr	(pr),(pr)
	desc9a	history_registers,128*4
	desc9a	ap|48,128*4
	tra	signaller$signaller	now give control to the signaller

" 

" Arrive Here If Fault Occurred While Running in the FIM.

die_die_die_:
	eppsb	pds$stack_0_ptr,*	get a pointer to the base of the ring 0 stack
" Try to preserve stack history in case the original fault was
" on the ring 0 stack.

	eppsp	sb|stack_header.stack_end_ptr,*  " where does it think it is?
	eax0	sp|0
	cmpx0	=o30000,du	reasonable ?
	tmoz	die_die_die_.use_end_ptr

	eppsp	sb|stack_header.stack_begin_ptr,* lay down frame at first available place
	sprisp	sb|stack_header.stack_end_ptr

die_die_die_.use_end_ptr:
	ldx7	push		get size of stack frame
	tsx0	fim_util$push_stack	make frame at base of pds

	lda	-1,du
	tra	die_die_die_.fake_ca

term_it:
	lda	bp|mc.scu.ca_word	get computed address
die_die_die_.fake_ca:
	ars	18		convert to fixed bin
	sta	temp		save in stack (temporary cell)
	szn	tc_data$wait_enable
	tze	wired_fim$unexp_fault
	eppap	terminate_proc$terminate_proc  kill this process
	spriap	call_ptr		..
	eppap	temp
	spriap	arglist+2
	fld	=1b24,dl		one argument
	ora	=o4,dl		make PL/1 calling sequence
	staq	arglist		..
	tra	call		make the call


" 

" Storage and Constants.

illegal_fault:			"transfer vector for illegal fault
	tra	fim_util$fault_trouble
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

" The following items must be filled in at
" system initialization time.

	segdef	lp,prs,scu,sig_prs,sig_scu

	even
lp:	its	-1,1		lp value for fim
prs:	its	-1,1		pointer to pds$fim_data
scu:	its	-1,1		pointer to pds$fim_data+24
sig_prs:	its	-1,1		pointer to pds$signal_data
sig_scu:	its	-1,1		pointer to pds$signal_data+24

push:	push			" used to get size of stack frame
cache_off:
	vfd	36/3			constant to turn off cache, luf time max
cache_to_reg_mode:
	oct	10003			constant  to dump cache to aq, luf time max
" 
" Tables indexed by cache size used for cache parity error diagnosis
 
c_sdw_bounds:			"template for last half of abs_seg sdw
	vfd	1/,o14/177,3/sdw.read,o18/sdw.unpaged  for 2k (L68) cache
	vfd	1/,o14/777,3/sdw.read,o18/sdw.unpaged  for 8k (DPS8) cache
	vfd	1/,o14/777,3/sdw.read,o18/sdw.unpaged  for 8k (DPS8 VS & SC) cache
	vfd	1/,o14/1777,3/sdw.read,o18/sdw.unpaged  for 16k (DPS8 VS & SC) cache
	vfd	1/,o14/3777,3/sdw.read,o18/sdw.unpaged  for 32k (DPS8 VS & SC) cache
c_lv_inc_tab:			" to increment cache levels
	vfd	o18/1000,18/0	for 2k (L68) cache
	vfd	o18/4000,18/0	for 8k (DPS8) cache
	vfd	o18/4000,18/0	for 8k (DPS8 VS & SC) cache
	vfd	o18/10000,18/0	for 16k (DPS8 VS & SC) cache
	vfd	o18/20000,18/0	for 32k (DPS8 VS & SC) cache
c_lv_st_mask:			" to mask to level 0 for start
	vfd	o18/776,18/0	for 2k (L68) cache
	vfd	o18/3776,18/0	for 8k (DPS8) cache
	vfd	o18/3776,18/0	for 8k (DPS8 VS & SC) cache
	vfd	o18/7776,18/0	for 16k (DPS8 VS & SC) cache
	vfd	o18/17776,18/0	for 32k (DPS8 VS & SC) cache
c_256k_mask:			" to mask cache addr within mod cache size
	vfd	o18/3776,18/0	for 2k (L68) cache
	vfd	o18/17776,18/0	for 8k (DPS8) cache
	vfd	o18/17776,18/0	for 8k (DPS8 VS & SC) cache
	vfd	o18/37776,18/0	for 16k (DPS8 VS & SC) cache
	vfd	o18/77776,18/0	for 32k (DPS8 VS & SC) cache
c_abs_addr_mask:			" to mask abs addr to mod cache size for SDW
	vfd	12/0,o15/77774,9/0	for 2k (L68) cache
	vfd	12/0,o15/77760,9/0	for 8k (DPS8) cache
	vfd	12/0,o15/77760,9/0	for 8k (DPS8 VS & SC) cache
	vfd	12/0,o15/77740,9/0	for 16k (DPS8 VS & SC) cache
	vfd	12/0,o15/77700,9/0	for 32k (DPS8 VS & SC) cache
c_lv_shift:			" to shift level info for saving
	dec	3		for 2k (L68) cache
	dec	5		for 8k (DPS8) cache
	dec	5		for 8k (DPS8 VS & SC) cache
	dec	6		for 16k (DPS8 VS & SC) cache
	dec	7		for 32k (DPS8 VS & SC) cache


"
" Dispatch Table for fim.
"	modified 1/7/76 by D. M. Wells to add neti condition
"	modified 2/26/76 by Noel I. Morris to place in separate segment.
"	modified July 77 by T. Casey to add susp and term.
"	modified Oct 77 by T. Casey to rename them to sus_ and trm_.
"	modified 7/79 by J. A. Bush for new signal_entry of fim and to merge back into the fim



"	Each entry in the dispatch table contains two words. The first
"	word has an entrypoint in the fim to transfer to to handle the fault
"	in the left half and a pointer relative to the linkage section of
"	an external entry to call in the right half. If the left half
"	is not standard, the right half is not defined.
"	The second word contains a relative pointer to the ACC string name
"	of the condition associated with the fault in the left half. The right
"	half contains flags, which currently are used to indicate 
"	the necessity of auditing this fault
"	(one or more bits in the left 15 bits of this field).
"	The presence of the low-order bit indicates that the time
"	for processing this fault should be accrued to virtual time.
"
"	___________________________________________
"	|                    |                    |
"	|  FIM handler       |  External handler  |
"	_|_____________________|_____________________|
"	|		 |		  |
"	|  ACC string ptr	 |	FLAGS	  |
"	_|_____________________|_____________________|
"
"
"	The following macro is used to generate entries in the dispatch table.
"	The unique string (label) is the value of the SCT index.

	macro	table
	zero	&1,&2
	vfd	18/&U,18/&4

	use	names
&U:	acc	"&3"

	use	main
"
	&end

	use	names
	use	main
	join	/text/main,names

" 


" External Links.

	link	am_fault_link,access_viol$am_fault
	link	ring_alarm_fault_link,ring_alarm$fault
	link	seg_fault_link,seg_fault$seg_fault
	link	hardware_fault_link,hardware_fault$hardware_fault
	link	boundfault_link,boundfault$boundfault
	link	linkage_fault_link,link_snap$link_fault
	link	owc_link,outward_call_handler$outward_call_handler
	link	stack_oob_handler,stack_oob_handler$stack_oob_handler


" 

	mod	8
eight_angry_zeros:
	dec	0,0,0,0,0,0,0,0

	even
fault_table:
	table	standard,hardware_fault_link,shutdown
	table	call_signaller,,store
	table	call_signaller,,mme1
	table	call_signaller,,fault_tag_1
	table	illegal_fault,,timer_runout
	table	command_fault,,command
	table	call_signaller,,derail
	table	call_signaller,,lockup
	table	illegal_fault,,connect
	table	standard,hardware_fault_link,parity
	table	illegal_procedure,,illegal_procedure
	table	standard,hardware_fault_link,op_not_complete
	table	standard,hardware_fault_link,startup
	table	split_overflow,,ovrflo
	table	call_signaller,,zerodivide
	table	illegal_fault,,execute
	table	standard.signaller_check_coll,seg_fault_link,seg_fault_error,1
pf_loc:	table	illegal_fault,,page_fault_error
	table	illegal_fault,,directed_fault_2
	table	call_signaller,,directed_fault_3
	table	access_violation,,accessviolation
	table	call_signaller,,mme2
	table	call_signaller,,mme3
	table	call_signaller,,mme4
	table	standard.signaller_check_coll,linkage_fault_link,linkage_error
	table	call_signaller,,fault_tag_3
	table	illegal_fault,,undefined_fault
	table	illegal_fault,,undefined_fault
	table	illegal_fault,,undefined_fault
	table	illegal_fault,,undefined_fault
	table	illegal_fault,,undefined_fault
	table	illegal_fault,,trouble

" 

" Additional entries for subcases of faults.

foc:	table	call_signaller,,illegal_opcode,access_audit_flag
null:	table	call_signal,,null_pointer
bam:	table	call_signaller,,illegal_modifier,access_audit_flag
avf:	table	call_signal,,illegal_ring_order,access_audit_flag
	table	call_signal,,not_in_execute_bracket,access_audit_flag
	table	call_signal,,no_execute_permission,access_audit_flag
	table	call_signal,,not_in_read_bracket,access_audit_flag
	table	call_signal,,no_read_permission,access_audit_flag
	table	call_signal,,not_in_write_bracket,access_audit_flag
	table	call_signal,,no_write_permission,access_audit_flag
	table	call_signal,,not_a_gate,access_audit_flag
	table	call_signal,,not_in_call_bracket,access_audit_flag
	table	standard.signal_check_coll,owc_link,outward_call
	table	call_signal,,bad_outward_call,access_audit_flag
	table	call_signal,,inward_return,access_audit_flag
	table	call_signal,,cross_ring_transfer
	table	standard.signal_check_coll,ring_alarm_fault_link,ring_alarm_fault,1
	table	standard,am_fault_link,am_fault
oob:	table	standard.signal_check_coll,boundfault_link,out_of_bounds,1
ovfl:	table	call_signaller,,fixedoverflow
eovf:	table	call_signaller,,overflow
eufl:	table	call_signaller,,underflow
trun:	table	call_signaller,,stringsize
ipr:	table	call_signaller,,illegal_procedure
stk_oob:	table	standard.signal_check_coll,stack_oob_handler,storage
ppf:	table	call_signal,,packed_pointer_fault
sppf:	table	call_signal,,lot_fault
	table	call_signal,,isot_fault
	table	call_signal,,system_packed_pointer
quit_loc:	table	call_signal,,quit
alrm_loc:	table	call_signal,,alrm
cput_loc:	table	call_signal,,cput
rqo_loc:	table	call_signal,,record_quota_overflow
size_loc: table	call_signaller,,size
	table	call_signal,,neti
com:	table	standard,hardware_fault_link,command
	table	call_signal,,sus_
	table	call_signal,,trm_
	table	call_signal,,wkp_
undefp:	table	call_signal,,undefined_pointer
	table	call_signal,,pgt_
	table	call_signal,,system_shutdown_scheduled_
	table	call_signal,,dm_shutdown_scheduled_
	table	call_signal,,system_message_
" 
	include	mc
" 
	include	stack_header
" 
	include	access_audit_flags
" 
	include	sdw
" 
	include	history_regs_dps8
" 
	include	history_regs_l68
" 
	include	bce_breakpoint_page
" 
	include	flagbox

"  BEGIN MESSAGE DOCUMENTATION
"
"  Message:
"  AUDIT (fim): access violation fault - ring ADDED_INFO
"
"  S:	$access_audit
"
"  T:	$run
"
"  M:	The specified process took an access violation fault
"	due to ring brackets inconsistant with the operation.
"
"  A:	$ignore
"
"
"  Message:
"  AUDIT (fim): access violation fault - mode ADDED_INFO
"
"  S:	$access_audit
"
"  T:	$run
"
"  M:	The specified process took an access violation fault
"	because the access mode was inconsistant with the operation.
"
"  A:	$ignore
"
"
"  Message:
"  AUDIT (fim): illegal procedure fault ADDED_INFO
"
"  S:	$access_audit
"
"  T:	$run
"
"  M:	The specified process took an illegal procedure fault.
"
"  A:	$ignore
"
"  END MESSAGE DOCUMENTATION
"
	end




		    fim_util.alm                    11/11/89  1139.5rew 11/11/89  0800.0      175860



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Bull Inc., 1987                *
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1983 *
" *                                                         *
" ***********************************************************


" FIM_UTIL - Utility subroutines for the fim, wired_fim, and ii.
"	consolidated 10/18/76 by Noel I. Morris
"	Modified 1 Feb 79 by D. Spector for new scs format for 8-cpu cioc
"	Modified 8/27/79 by J. A. Bush to reorganize the check_fault subroutine
"	Modified 8/25/80 by J. A. Bush for the DPS8/70M CPU
"	Modified 2/23/81 by J. Bongiovanni for fast connect code
"	Modified 3/5/81 by J. Bongiovanni for OOSB on prds
"	Modified 3/23/81 by J. A. Bush to dump extended APU history reg. for DPS8/70M.
"	Modified 9/23/81 by J. A. Bush to not use QU mode when saving AMs
"	Modified 10/28/81 by J. Bongiovanni for bug in check_fault
"	Modified 2/8/82 by J. Bongiovanni to trap on masked in user ring (conditionally)
"	Modified 02/16/82 by J. A. Bush to not trash mc.fault_reg for sys_trouble crash
"	Modified 07/30/82 by J. Bongiovanni for scs$trouble_processid
"	Modified 10/13/82 by E. N. Kittlitz to clear indicators in v_time_init.
"	Modified sometime by B. I. Margulies for bootload multics.
"	Modified 4/7/83 by E. N. Kittlitz for drl_fault_trouble.
"	Modified 10/8/83 by J. A. Bush to dump extended fault register
"	Modified 10/18/83 by R. Coppola to meter per-processor cache errors 
"	Modified 11/27/83 by E. N. Kittlitz for ext vcpu entries
"         Modified 83-12-05 by BIM for checking fault-masked always.


" HISTORY COMMENTS:
"  1) change(88-05-24,Farley), approve(88-06-30,MCR7927),
"     audit(88-07-12,Fawcett), install(88-08-02,MR12.2-1076):
"     Added checking in force_hist_regs for the new prds$hregs_last_saved time
"     and in save_fault_reg for prds$fault_reg_last_saved.  This is to prevent
"     multiple attempts to save the data, resulting in the data becoming zero.
"                                                      END HISTORY COMMENTS


	name	fim_util


	segdef	check_fault	validate a fault
	segdef	check_interrupt	validate an interrupt
	segdef	fault_trouble	illegal fault condition
	segdef	drl_fault_trouble   illegal fault, you say what it is
	segdef	copy_mc		copy machine conditions
	segdef	push_stack	push stack frame
	segdef	push_stack_32	push stack frame with grace area
	segdef	set_mask		set controller mask to sys level
	segdef	restore_mask	restore previous controller mask
	segdef	hist_regs		save history regs and AMs
	segdef	force_hist_regs	force save history regs and AMs
	segdef	check_mct		check and trace machine conditions and hregs
	segdef	reset_mode_reg	turn on hist reg and cache
	segdef	v_time_init	start virtual time meter
	segdef	fim_v_time_init	save virtual time for FIM
	segdef	v_time_calc	stop virtual time meter
	segdef	fim_v_time_calc	compute virtual time for FIM

	entry	fim_v_time_calc_ext	externally callable fim_v_time_calc
	entry	fim_v_time_init_ext	externally callable fim_v_time_init

	link	prds_link,prds$+0


	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Procedure to check validity of faults and interrupts
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

check_fault:
	ldaq	pds$apt_ptr	get pointer to our APT entry
	cmpaq	prds$idle_ptr	are we in idle process?
	tze	idle_trouble	if so, stop the entire system at once

	lxl1	prds$processor_tag
	lprpab	scs$mask_ptr,1
	xec	scs$read_mask,1
	cmpaq	scs$sys_level	masked to system level
	tze       fault_masked_trouble

check_interrupt:
	lda	bp|mc.scu.ppr.prr_word  check whether running in ring-0
	cana	scu.ppr.prr_mask,du	ring number in ppr
	tnz	not_invalid	not ring-0

	eax7	0		nothing invalid yet
	lda	bp|mc.prs+6*2	1st word of stack pointer
	ldq	=o77777,dl	mask to check seg-no and val. ring
	cmk	lp|prds_link	is stack=prds and ring-0
	tnz	not_on_prds	no
	ldx7	-trbl_prds_fi,du	fault on prds

	lda	bp|mc.scu.tpr.tsr_word	now check for stack overflow
	ldq	=o777777,dl	ring number, segment number in TSR
	cmk	lp|prds_link	was target prds
	tnz	not_on_prds	no
	lda	bp|mc.scu.fault_data_word  stack overflow is OOSB
	cana	scu.fd.oosb,du	is it possibly OOSB (must also be acv)
	tze	not_on_prds	not at all
	ana	scu.fi_num_mask+scu.fi_flag_mask,dl  check fault type
	cmpa	2*FAULT_NO_ACV+1,dl	fault/access violation
	tze	oosb_prds_trouble	on the prds!
	
not_on_prds: 
	lda	pds$processid	do we have ptr locked
	cmpa	sst$ptl
	tnz	not_ptl_locked	no
	ldx7	-trbl_ptl_fi,du	f/i with ptl locked
	
not_ptl_locked:
	eaa	0,7		any invalid condition found
	tze	not_invalid	no
	ars	18		set up sys_trouble_pending
	tra	check_fault_trouble ..
	
not_invalid: 		
	lca	scu.ir.parm+1,dl	turn OFF parity mask
	ansa	bp|mc.scu.indicators_word

	tra	0,0		return to caller

idle_trouble:
	lca	trbl_idle_flt,dl	fault while in idle process
	tra	check_fault_trouble	..

fault_masked_trouble:
	lca	trbl_fault_masked,dl fault while masked to system level
	tra	check_fault_trouble

oosb_prds_trouble:
	lca	trbl_oosb_prds,dl	yes--oosb on prds (stack overflow)
	tra	check_fault_trouble ..

fault_trouble:
	lca	trbl_illeg_flt,dl	unrecognized fault
	tra	check_fault_trouble

drl_fault_trouble:
	lca	trbl_r0_drl_flt,dl  ring 0 derail
	tra	check_fault_trouble

check_fault_trouble:
	sta	scs$sys_trouble_pending  set trouble flags

	lda	pds$processid		save our process ID
	stac	scs$trouble_processid	if we're the first

	tsx1	save_fault_reg		save fault reg and cpu type

	lda	sys_info$initialization_state Too early for connect?
	cmpa	=2,dl			Multiprocessing?
	tmoz	sys_trouble$sys_trouble	Go directly to jail ...

	lxl1	prds$processor_tag	prepare to send connect
	cioc	scs$cow_ptrs,1* 	ZAP

	dis	*		cannot inhibit connects at a DIS
	tra	-1,ic		STOP
" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	COPY_MC - Procedure to copy machine conditions
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

copy_mc:
	mlr	(pr),(pr)		copy machine conditions
	desc9a	bp|0,48*4
	desc9a	ap|0,48*4
	eppbp	ap|0		make bp -> copied conditions

	tra	0,0		return to caller



" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	PUSH_STACK - Procedure to create a stack frame
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

push_stack:
	eppap	sb|stack_header.stack_end_ptr,*  ap -> place for frame
push_join:
	sprisp	ap|stack_frame.prev_sp	save current sp
	eppsp	ap|0			set sp to new frame
	eppap	sp|0,7			ap -> end of frame
	spriap	sp|stack_frame.next_sp	save next sp
	spriap	sb|stack_header.stack_end_ptr	save end pointer
	sprilp	sp|stack_frame.lp_ptr	save our linkage ptr

	tra	0,0			return to caller


push_stack_32:
	eppap	sb|stack_header.stack_end_ptr,*  ap -> place for frame
	eppap	ap|32		leave room for push in progress
	tra	push_join		join common code

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Procedures to save and restore controller masks
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

set_mask:
	lxl1	prds$processor_tag	processor tag in X1
	lprpab	scs$mask_ptr,1	get pointer for masking
	xec	scs$read_mask,1	read mask, if assigned
	staq	bp|mc.mask	save it

	lxl1	prds$processor_tag	CPU tag in X1
	lprpab	scs$mask_ptr,1	get pointer for masking
	ldaq	scs$sys_level	going to mask all interrupts
	xec	scs$set_mask,1	only if mask is assigned

	tra	0,0



restore_mask:
	lxl1	prds$processor_tag	CPU tag in X1
	lprpab	scs$mask_ptr,1	get pointer for masking
	ldaq	bp|mc.mask	get original mask
	oraq	channel_mask_set	make sure channel mask is correct
	anaq	scs$open_level	..
	xec	scs$set_mask,1	restore the mask

	tra	0,0		return to caller


	even
channel_mask_set:
	oct	17,17

" 
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Procedures to save history regs. Enter with bb -> place to store history regs.
"	hist_regs - 	save history regs only if per-system 
"			(wired_hardcore_data$global_hregs) or per-process
"			(pds$save_history_regs) flags are set.
"	force_hist_regs -	save history regs unconditionaly
"
"	X4 is set  with the cpu type (0 = L68/DPS, 1 = DPS8) by the
"	save_fault_reg subroutine  which is called by the check_mct subroutine
"	which is called by all callers of this subroutine.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

hist_regs:
	szn	wired_hardcore_data$global_hregs is global history reg save flag on?
	tmi	force_hist_regs		xfer if yes
	szn	pds$save_history_regs	no, is per_process hregs switch on?
	tmi	force_hist_regs		xfer if yes
	stz	pds$hregs_saved		no, zero switch for signaller
	tra	0,0			and return to caller

force_hist_regs:
	ldaq	bp|mc.fault_time		check fault time
	ana	=o777777,dl		only lower 54 bits
	cmpaq	prds$hregs_last_saved 	against last time saved
	tmoz	0,0			return if already saved
	staq	prds$hregs_last_saved	set to fault time if not
	lda	=o400000,du		set hreg saved switch
	sta	pds$hregs_saved		for signaller
	tsx1	save_am			go save associative memory
	ldq	2,du			get a 2 for stepping address
	eax6	4			4 blocks of
scpr1:	eax7	16			16 history registers
	eax3	0			set up for L68 CPU type initally
	cmpx4	1,du			is this a DPS8/70M CPU?
	tnz	scpr2			xfer if no, it is L68
	eax3	48			yes, set up to skip first 48 hregs
scpr2:	lda	scpr-1,6			get correct instruction
	sta	bp|mc.fim_temp		save in stack
scpr3:	xec	bp|mc.fim_temp		execute the instruction
	cmpx3	0,du			are we through skipping hregs?
	tze	scpr4			yes, go increment address
	eax3	-1,3			no, skip another
	tra	scpr3			and go execute scpr again

scpr4:	asq	bp|mc.fim_temp		increment address of instruction
	eax7	-1,7			count down
	tnz	scpr3			more of this 16 double word block
	eax6	-1,6			count down
	tnz	scpr1			another kind of hreg

	eax7	64			initially set clear count to 64
	cmpx4	1,du			is this a DPS8/70M CPU?
	tze	*+2			yes, clear all 64 hregs
	eax7	16			no, clear only 16 hregs
	lcpr	0,03			set all history regs to zero
	eax7	-1,7			count down
	tpnz	*-2			xfer if more to do
	tra	0,0			return to caller

scpr:	scpr	bb|0,40			OU History Regs for L68, OU/DU for DPS8
	scpr	bb|32,20			CU History Regs
	scpr	bb|64,10			DU History Regs for L68, extended APU for DPS8
	scpr	bb|96,00			APU History Regs

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Internal subroutine for saving fault register, extended fault 
"	register and CPU type (from RSW (2)), int the machine condition area.
"	entry via tsx1 save_fault_reg. Exit with x4 containing the CPU type
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

save_fault_reg:
	ldaq	bp|mc.fault_time		check fault time
	ana	=o777777,dl		only lower 54 bits
	cmpaq	prds$fault_reg_last_saved 	against last time saved
	tmoz	0,1			return if already saved
	staq	prds$fault_reg_last_saved	set to fault time if not
	scpr	bp|mc.fim_temp,01		store the fault register
	ldaq	bp|mc.fim_temp
	sta	bp|mc.fault_reg		save M.S. 36 bits
	rsw	2			get cpu type in a
	arl	30			position in al
	ana	3,dl	
	eax4	0,al			save cpu type in x4
	lrl	mc.cpu_type_shift		merge with ext. fault reg
	stcq	bp|mc.cpu_type_word,70	and save in M.C.
	lda	prds$processor_tag		get cpu num
	xec	cache_ctr_tab,al		lb=> per-cpu cache err ctrs	
	lda	bp|mc.fault_reg		reload PFR
	ana	=o10,dl			cache dir parity (bit 32)?
	tze	check_efr			no, go check EFR
	aos	lb|1			yes, increment the per-cpu ctr
check_efr:
	anq	mc.ext_fault_reg_mask,du	mask unwanted bits OFF
	tze	0,1			no bits on, return
	qls	2			get EFR bits in Q 1-17
	eaa	0			set up A as incrementer
efr_loop:
	ada	1,dl			increment EFR slot number
	qls	1			is this bit on?
	tpnz	efr_loop			no, but some other bit on
	tze	0,1			no more EFR bits, return
	aos	lb|1,al			increment EFR counter
	tra	efr_loop			look for nxt EFR bit

cache_ctr_tab:
	epplb	wired_hardcore_data$cpu_a_cache_err_ctr_array
	epplb	wired_hardcore_data$cpu_b_cache_err_ctr_array
	epplb	wired_hardcore_data$cpu_c_cache_err_ctr_array
	epplb	wired_hardcore_data$cpu_d_cache_err_ctr_array
	epplb	wired_hardcore_data$cpu_e_cache_err_ctr_array
	epplb	wired_hardcore_data$cpu_f_cache_err_ctr_array
	epplb	wired_hardcore_data$cpu_g_cache_err_ctr_array
	epplb	wired_hardcore_data$cpu_h_cache_err_ctr_array
" 
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Internal subroutine for saving associative memory in the prds
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

save_am:
	eax3	4			4 instructions to execute
	eax6	3			initialy set for DPS8 (4 sets of 16)
	cmpx4	1,du			is it a DPS8 CPU?
	tze	sam1			yes, go execute code
	eax6	0			no, only 1 set for each type on L68

sam1:	xec	samt1-1,3			load LB with proper AM type
	lda	samt2-1,3			load instruction to execute in A
	sta	bp|mc.fim_temp		and save
	eax7	0,6			initialize counter
sam2:	eaq	0,7			copy to qu
	qls	4			multiply by 16
	cmpx3	2,du			is it for sdw_am_regs?
	tnz	*+2			xfwr if no
	qls	1			yes, make it times 32
	stcq	bp|mc.fim_temp,30		set quad offset
	xec	bp|mc.fim_temp		execute instruction
	eax7	-1,7			count down
	tpl	sam2			do next set
	eax3	-1,3			count down instructions to exucute
	tnz	sam1			go do next instuction set
	tra	0,1			return to caller

samt1:	epplb	prds$sdw_am_ptrs
	epplb	prds$sdw_am_regs
	epplb	prds$ptw_am_ptrs
	epplb	prds$ptw_am_regs

samt2:	ssdp	lb|0
	ssdr	lb|0
	sptp	lb|0
	sptr	lb|0

"

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Procedure to check if conditions are met for machine condition tracing
"	if conditions are not true for machine condition tracing, return is ic +1 (tra	0,0)
"	if conditions are met for machine condition tracing, then
"	return is ic +2 (tra   1,0), bb -> place to pick up history regs and
"	lb -> place to pick up machine conditions directly from machine condition trace buffer
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

check_mct:
	tsx1	save_fault_reg		save fault reg and get CPU type in x4
	szn	pds$mc_trace_sw		is this process tracing machine conditions?
	tpl	0,0			return to caller if no
	szn	pds$mc_trace_seg		Does user want to trace all M. Cs?
	tze	cp_hregs			xfer if seg number zero
	lda	bp|mc.scu.ppr.psr_word	look at the psr
	ana	scu.ppr.psr_mask,du		and out  everything except psr
	cmpa	pds$mc_trace_seg		compare psr to object we are tracing
	tze	cp_hregs			xfer if psr = object we are tracing
	lda	bp|mc.scu.tpr.tsr_word	look at tsr
	ana	scu.tpr.tsr_mask,du		and out everthing except tsr
	cmpa 	pds$mc_trace_seg		compare tsr to object we are tracing
	tnz	0,0			return to caller if psr or tsr don't have seg
cp_hregs:
	lprplb	pds$mc_trace_buf		get packed ptr to wired trace buffer
	stx0	lb|mctseg.x0save		safe store return address
	lxl5	lb|mctseg.hr_nxtad		x5 = rel ptr to next H. R. storage location
	cmpx5	lb|mctseg.hr_lim		do we have to roll over the trace?
	tmi	hr_roll			xfer if no
	ldx5	lb|mctseg.hr_strt		yes, pick up initial storage location
	sxl5	lb|mctseg.hr_nxtad		store new location
hr_roll:
	eax5	mctseg.hr_size,5		increment storage location
	sxl5	lb|mctseg.hr_nxtad		set rel ptr to next H. R. storage location
	eppbb	lb|-mctseg.hr_size,5	bb -> current HR storage location
	tsx0	force_hist_regs		go save history regs in mc_trace buf
	lprplb	pds$mc_trace_buf		get packed ptr to wired trace buffer
	ldx0	lb|mctseg.x0save		restore return address
	lxl5	lb|mctseg.mc_nxtad		x5 = rel ptr to next M. C. storage location
	cmpx5	lb|mctseg.mc_lim		do we have to roll over the trace?
	tmi	mc_roll			xfer if no
	ldx5	lb|mctseg.mc_strt		yes, pick up initial storage location
	sxl5	lb|mctseg.mc_nxtad		store new location
mc_roll:
	eax5	mctseg.mc_size,5		increment storage location
	sxl5	lb|mctseg.mc_nxtad		set rel ptr to next M. C. storage location
	epplb	lb|-mctseg.mc_size,5	lp -> current MC storage location
	mlr	(pr),(pr)			move the data to wired buffer
	desc9a	bp|0,mctseg.mc_size*4
	desc9a	lb|0,mctseg.mc_size*4
	tra	1,0			return to caller at ic +2


" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Procedure to reset mode registers to continue strobing
"	data into the history registers.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

reset_mode_reg:
	epplb	prds$cache_luf_reg	point to cache/luf reg setting
	lcpr	lb|0,02		set cache enable and full luf time

	lda	prds$mode_reg	retrieve template mode reg
	ora	mr.enable_mr+mr.enable_hist,dl  enable mode reg and enable hist regs
	sta	prds$mode_reg_enabled	save this mode reg value
	epplb	prds$mode_reg_enabled	get pointer to temp mode reg value
	lcpr	lb|0,04		reload the mode register
	tra	0,0			return to caller

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Procedures to suspend virtual time metering
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	even			anyone know why we do this?
v_time_init:
	tsx7	get_times		get fault time and virtual time

	ldi	0,dl		clear indicators as a service to our caller
	aos	pds$vtime_count	step virtual time count
	tpnz	0,0		if already set, don't meter

	staq	pds$time_v_temp	save for later
	tra	0,0



	odd			or this? actually, just why are they different?
fim_v_time_init:
	tsx7	get_times		get times

	ldi	0,dl		clear indicators as a service to our caller
	szn	pds$vtime_count	metering already?
	tpl	0,0		if so, return

	staq	pds$fim_v_temp	save current virtual time
	ldaq	pds$virtual_delta	save current delta
	staq	pds$fim_v_delta	..
	tra	0,0		and return to caller


fim_v_time_init_ext:
	eppbp	ap|2,*		let get_times clobber first arg
	eppbp	bp|-mc.fault_time	...
	tsx0	fim_v_time_init
	ldaq	pds$fim_v_temp	now, just like pds copies pds cells to stack...
	staq	ap|2,*		we drop them as output arguments
	ldaq	pds$fim_v_delta
	staq	ap|4,*
	short_return


	even
get_times:
	rccl	sys_info$clock_,*	read the clock
	staq	bp|mc.fault_time	save time of fault/interrupt
	sbaq	pds$cpu_time	compute virtual time
	tra	0,7		return to caller

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Procedures to reinstate virtual time metering
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	even
v_time_calc:
	lca	1,dl		decrement virtual time count
	asa	pds$vtime_count	..
	tpl	0,0		if others, don't meter

v_calc_join:
	rccl	sys_info$clock_,*	read the clock
	adl	96,dl		add in correction delta
	sbaq	pds$cpu_time	get current value of CPU time
	sbaq	pds$time_v_temp	get time we used
	staq	pds$time_v_temp	save temporarily

	adaq	pds$virtual_delta	compute virtual time increment
	staq	pds$virtual_delta	and save

	ldaq	pds$time_v_temp	time used in AQ again
	adaq	tc_data$delta_vcpu	compute total vcpu time
	staq	tc_data$delta_vcpu	..

	tra	0,0



	even
fim_v_time_calc:
	szn	pds$vtime_count	metering virtual time?
	tpl	0,0		if not, just return

	ldaq	pds$virtual_delta	get current virtual delta
	sbaq	pds$fim_v_delta	subtract original delta
	adaq	pds$fim_v_temp	correct FIM time
	staq	pds$time_v_temp	store corrected time
	tra	v_calc_join	join common code


fim_v_time_calc_ext:
	ldaq	ap|2,*		copy automatic values back to pds just like fim
	staq	pds$fim_v_temp
	ldaq	ap|4,*
	staq	pds$fim_v_delta
	tsx0	fim_v_time_calc
	short_return
" 

	include	stack_frame

" 

	include	stack_header
	include	mctseg

" 

	include	sys_trouble_codes

	include	mode_reg

	include	mc

" 

	include	fault_vector



	end




		    iom_interrupt.alm               11/11/89  1139.5r w 11/11/89  0801.2       77229



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Bull Inc., 1987                *
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1982 *
" *                                                         *
" * Copyright (c) 1972 by Massachusetts Institute of        *
" * Technology and Honeywell Information Systems, Inc.      *
" *                                                         *
" ***********************************************************

" iom_interrupt:  IOM interrupt handler
" Stolen from iom_manager and ii November 1980 by C. Hornig
" Added loop protocol for IOM switch checking, January 1985 by M. Pandolf
"	see iom_connect$connect_and_identify for the other half of the protocol

	name	iom_interrupt

	segdef	interrupt_entry	" interrupt vector transfers here
	segdef	iilink		" ITS ptr to linkage section
	segdef	prds_prs		" ITS ptr to space for spri
	segdef	prds_scu		" ITS ptr to space for SCU

	tempd	hlr_arglist(4)	" argument list for interrupt handler
	tempd	time		" time handler called
	tempd	imw_save		" current IMW for scan
	temp	int_level		" interrupt level for handler (1 3 5 7)
	temp	index		" index for this channel
	temp	chantab_base	" offset in chantab for this IOM
	temp	device		" offset in per_device for this channel
	temp	chx		" channel index from chantab
	temp	int_count		" handlers called this time around

" Index register conventions:

"	X0 - internal subroutine calls.
"	X1 - index into devtab.
"	X2 - index into mailbox.
"	X3 - Used to index iomd.per_iom.
"	X4 - interrupt cell #.
"	X5 - interrupt level #.
"	X6 - index in status queue

" Pointer Register Conventions:

"	AP -> machine conditions
"	AB -> inetrnal calls
"	BP -> <iom_data>|0
"	BB -> mailbox for this IOM.
"	LP -> linkage section
"	LB -> status queue


" These are initialized by initialize_faults

	even
iilink:	its	-1,1		" our LP
prds_prs:	its	-1,1		" where to store PRs
prds_scu:	its	-1,1		" and CU info

three_args_nd:
	zero	6,4
zero:	zero	0

push_value:
	push

chanpos:				" table of chantab offsets
	zero	0,0*4*per_iom_size+32
	zero	0,1*4*per_iom_size+32
	zero	0,2*4*per_iom_size+32
	zero	0,3*4*per_iom_size+32
	zero	0,0*4*per_iom_size
	zero	0,1*4*per_iom_size
	zero	0,2*4*per_iom_size
	zero	0,3*4*per_iom_size
" 
" This entry is transferred to by the interrupt vector.
" It is responsible for calling the interrupt handlers of various DIM's
" for which interrupts have been stored in the IMW array.
" It calls the interrupt routine as follows:
"	call int_proc (idx, int_level, data_word)
" where int_level (1 3 5 7) corresponds to the level passed by the channel
" to the IOM and data_word in the system fault or special status word.

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+><+>

interrupt_entry:
	spri	prds_prs-*,ic*	" save pointer registers
	eppbp	prds_prs-*,ic*	" ab -> machine conditions
	sreg	bp|mc.regs	" save registers
	lxl7	bp|mc.scu.indicators_word
	canx7	scu.ir.mif,du	" check for EIS
	tze	2,ic		" so we can save
	spl	bp|mc.eis_info	" the pointers and lengths

	epplp	iilink-*,ic*	" set up LP

	tsx0	fim_util$v_time_init " meter virtual time

	tsx0	fim_util$check_interrupt " make sure we're not not prds

	tsx0	fim_util$check_mct	" go save M.C.s and hregs
				" if trace is on
	nop			" return ic +1

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Establish a stack frame and mask interrupts.
"
	epbpsb	prds$		" use prds
	ldx7	push_value-*,ic	" get size of stack frame
	tsx0	fim_util$push_stack	" push the frame

	tsx0	fim_util$set_mask	" mask to sys level

	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	tsx0	fim_util$reset_mode_reg
				" turn on hist regs and cache
	ldq	bp|mc.scu.fault_data_word
	anq	scu.fi_num_mask,dl	" get the interrupt number
	qrl	scu.fi_num_shift
	eax4	0,ql		" interrupt cell in X4
" 
	anq	=7,dl		" get base channel table position
	lda	chanpos,ql
	sta	chantab_base	" save it for later

	eaa	0,x4		" get interrupt cell
	arl	18+2		" interrupt level in AL
	ora	=1,dl		" always odd
	sta	int_level		" save for handler

	ldaq	three_args_nd-*,ic	" Build argument list for handler
	staq	hlr_arglist	" call handler (index, int_level, ""b)
	epplb	index
	sprilb	hlr_arglist+2
	epplb	int_level
	sprilb	hlr_arglist+4
	epplb	zero-*,ic
	sprilb	hlr_arglist+6
"
"	set up to search IMW area
"
	eppbp	iom_data$
	stz	int_count		" no interrupts yet

"
"	wait until any IOM switch checking is completed
"

imw_wait:
	odd
	ldac	bp|iom_data.imw_lock
	tze	-1,ic		" loop while lock in transition
	tpl	imw_read
	sta	bp|iom_data.imw_lock" restore -1 into lock
	tra	imw_wait		" and continue looping

imw_read:
	aos	bp|iom_data.n_intr_procs " bump number of cpus handling interrupts
	aos	bp|iom_data.imw_lock " was 0 from ldac, now is 1

	ldac	iom_mailbox$+iom_mailbox_seg.imw_array_word,x4
	tze	null_int-*,ic	" no IMW bit set

	ldq	0,du		" make a fake float number
	lde	0,du
	lrl	1
	tra	imw_begin-*,ic	" start scanning

" Scan the IMW for any bits on and process these interrupts.

imw_retry:
	dfld	imw_save		" get back remaining bits
	tze	interrupt_return	" no bits left

imw_begin:
	ldi	0,dl		" clear hex and overflow bits
	fno
	era	=o200000,du	" clear the bit
	dfst	imw_save

	lda	imw_save		" get channel number
	ars	36-8		" in AL
	neg	0
	ada	chantab_base	" add chantab offset
	sta	index		" store in case of error

	mrl	(pr,al),(pr),fill(0) " Reference the channel table.
	desc9a	bp|iom_data.per_iom+per_iom.chantab_word,1
	desc9a	chx,4		" Word will be leading zero padded.

	eppap	hlr_arglist

	ldq	chx		" chx in QL
	tze	invalid_int-*,ic	" Ignore interrupt if channel not assigned.
	mpy	per_device_size,dl
	eax1	-per_device_size,ql	" index into per_device

	lda	bp|iom_data.per_device+per_device.flags,x1
				" is there a handler?
	cana	per_device.in_use,du
	tze	invalid_int-*,ic	" Return if no handler assigned.

	lda	bp|iom_data.per_device+per_device.index,x1
	sta	index		" save the handler's index
	stx1	device		" save per_device index for ext. call

	rccl	sys_info$clock_,*	" Get int_time now.
	staq	time		" And save it.

	short_call bp|iom_data.per_device+per_device.handler,x1*
				" Call handler.

	rccl	sys_info$clock_,*	" Get int_time again.
	sbaq	time		" Compute delta.

	eppbp	iom_data$		" re-establish addressability
	ldx1	device		" restore per_device offset
	adaq	bp|iom_data.per_device+per_device.interrupt_time,x1
	staq	bp|iom_data.per_device+per_device.interrupt_time,x1
	ldaq	bp|iom_data.per_device+per_device.interrupts,x1
	adl	=1,dl		" update meters
	staq	bp|iom_data.per_device+per_device.interrupts,x1
	aos	int_count		" count interrupts

	tra	imw_retry-*,ic	" find more interrupts


invalid_int:
	aos	bp|iom_data.invalid_interrupts
				" meter unexpected interrupts
	short_call iom_error$invalid_interrupt
				" and tell the world
	eppbp	iom_data$		" re-establish addressability
	tra	imw_retry-*,ic	" find more channels
" 
null_int:				" meter interrupts with null IMW
	aos	bp|iom_data.null_interrupts

interrupt_return:
	lda	int_count		" meter multiple interrupts
	cmpa	=1,dl
	tmoz	2,ic
	aos	bp|iom_data.multiple_interrupts

	ldaq	tc_data$interrupt_count
	adl	1,dl		" count interrupts
	staq	tc_data$interrupt_count

	odd
	ldac	bp|iom_data.imw_lock
	tze	-1,ic		" loop while lock in transition

	lcq	1,dl		" decrement count of cpus in interrupt handler
	asq	bp|iom_data.n_intr_procs

	sta	bp|iom_data.imw_lock

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Relinquish stack frame and open interrupt mask.
"
	eppbp	prds_prs-*,ic*	" restore MC ptr

	tsx0	fim_util$restore_mask
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

	epbpsb	sp|0		get ptr to base of stack
	sprisp	sb|stack_header.stack_end_ptr  pop our stack frame

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Perform interrupt metering and exit.
"
	ldaq	bp|mc.fault_time	" get fault time
	ana	=o777777,dl	" clear CPU type
	staq	prds$iitemp	" save for now
	rccl	sys_info$clock_,*	" read the clock
	sbaq	prds$iitemp	" compute real time spent
	adaq	tc_data$interrupt_time " add in to total
	staq	tc_data$interrupt_time "	..

	odd
	tsx0	fim_util$v_time_calc " compute virtual time

	lxl1	bp|mc.scu.indicators_word
	canx1	scu.ir.mif,du	" check for EIS if not don't reload pl
	tze	2,ic
	lpl	bp|mc.eis_info	restore pointers and lengths
	lreg	bp|mc.regs	and registers
	lpri	prds_prs-*,ic*	restore prs
	rcu	prds_scu-*,ic*	and dismiss the interrupt
" 
	include	iom_data
	include	mc
	include	stack_header

	end




		    sys_trouble.alm                 11/11/89  1139.5r w 11/11/89  0801.2      115587



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Bull Inc., 1987                *
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1982 *
" *                                                         *
" * Copyright (c) 1972 by Massachusetts Institute of        *
" * Technology and Honeywell Information Systems, Inc.      *
" *                                                         *
" ***********************************************************

" HISTORY COMMENTS:
"  1) change(87-01-19,Fawcett), approve(87-01-19,MCR7531),
"     audit(87-01-19,Martinson), install(87-01-20,MR12.0-1288):
"     Change to set the bb pointer before it is used. Also add segdef sys_trouble.
"                                                      END HISTORY COMMENTS


inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

	use	main


" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	Before spinning waiting for console I/O to die, and before going to
"	bce, the fault vector for lockup is patched to do an SCU/RCU
"	in absolute mode. This must be in absolute mode, in case the lockup
"	happens in early bce. The target of the SCU/RCU is in this program
"	rather than prds$ignore_data, since the latter may not be in the
"	low-order 256K.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
	eight
ignore_data:
	bss	,8		" SCU data for SCU/RCU on lockup fault

ignore_scu_rcu:
	scu	0		" Put into fault vector for lockup fault
	rcu	0		" after absolute address inserted into Y-field

" 
	segdef	sys_trouble
sys_trouble:
	lda	prds$processor_pattern  get bit pattern for this CPU
	cana	scs$bos_restart_flags  are we restarting this processor?
	tnz	restart		if so, get it running again


"	If this is the first processor to enter this code,
"	a system trouble connect must be sent to all other
"	processors to stop them too.

	lda	scs$processor	get flags for all running CPU's
	stac	scs$trouble_flags	are we the first processor?
	tnz	*+2		if not, skip broadcast
	tsx0	broadcast		broadcast system trouble connects to others

	tsx0	fim_util$set_mask	save mask and mask down

" 

"	Copy the machine conditions into prds$sys_trouble_data.
"	This prevents overwriting the data when another
"	system trouble interrupt is used to restart CPU's.

	lda	bp|mc.scu+scu.fi_num_word  get fault code
	ana	scu.fi_num_mask,dl	mask fault code
	arl	scu.fi_num_shift	right-justify
	cmpa	FAULT_NO_CON,dl	connect fault?
	tnz	no_copy		if not, conditions already in trouble_data

	eppap	prds$sys_trouble_data  ap -> cache for machine conditions
	tsx0	fim_util$copy_mc	copy the machine conditions
no_copy:

	eppbb	pds$history_reg_data	bb -> place to store history regs
	tsx0	fim_util$check_mct		go copy cpu type into machine conditions
	tsx0	fim_util$force_hist_regs	save the history registers in pds

	lda	prds$processor_tag	CPU tag in A
	als	1		multiply by 2
	sdbr	scs$trouble_dbrs,al	save DBR for debugging


"	If this is the bootload CPU, enter bce.
"	Otherwise, die gracefully.

	lca	1,dl		all one's in A
	era	prds$processor_pattern  CPU pattern mask in A
	ansa	scs$processor	indicate that this CPU is stopped

	lda	prds$processor_tag	processor tag in A
	cmpa	scs$bos_processor_tag  is this the bootload CPU?
	tze	enter_bce		if so, go to bce

die:
	dis	-1,du		stop 
	tra	*-1		I said stop!

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	The second trouble connect for restarting processors
"	causes control to be transferred here.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

restart:
	lda	prds$processor_pattern  get bit for this processor
	orsa	scs$processor	indicate CPU is running again
	era	=-1		complement to make a mask
	ansa	scs$bos_restart_flags  indicate processor has been restarted
	ansa	scs$sys_trouble_pending  turn off trouble flag for this processor

	eppbp	wired_fim$trouble_prs,*  bp -> system trouble m.c. area
	tsx0	fim_util$restore_mask  restore original controller mask

	szn	scs$faults_initialized  see if system ready for cache
	tze	trouble_exit	transfer if not
	tsx0	fim_util$reset_mode_reg  restore mode and cache mode regs

	odd
trouble_exit:
	tsx0	fim_util$v_time_calc  start virtual time meters again

	lpl	bp|mc.eis_info	restore ptrs and lgths
	lreg	bp|mc.regs_word	and regs
	lpri	bp|mc.prs		and prs
	rcu	wired_fim$trouble_scuinfo,*	get running again

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	The following code copies an error message into the bce
"	flagbox message buffer.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

enter_bce:
	lda	scs$sys_trouble_pending  get flags
	als	18		extract low-order
	ars	18		could be negative number
	neg	0		or zero
	tze	rtb_no_message	if zero, no messag
	eppbb	flagbox$		bb -> bce flagbox
	cmpa	trbl_exec_flt,dl
	tnz	not_manual_crash	execute fault?
	ldq	fgbx.manual_crash,du
	orsq	bb|fgbx.rtb
not_manual_crash:
	mlr	(),(pr)		copy program ID
	desc9a	sys_trouble_name,13
	desc9a	bb|fgbx.message,13

	mlr	(id),(pr),fill(040)	copy error message
	arg	trouble_messages-1,al
	desc9a	bb|fgbx.message+3(1),64-13

	cmpa	trbl_r0_drl_flt,dl	is it a ring-0 derail?
	tnz	non_drl		nope, that's all 
	szn	scs$drl_message_pointer augment the message
	tze	non_drl		nothing to say
	lprplb	scs$drl_message_pointer 
	lda	lb|0		acc length in upper 9
	arl	27		lower 9, now
	mlr	(pr,rl),(pr),fill(040) Your life story in 32 characters.
	desc9a	lb|0(1),al
	desc9a	bb|fgbx.message+8,64-32

non_drl:	ldq	fgbx.mess+fgbx.alert,du  set flags for message printing
	orsq	bb|fgbx.rtb	..

	tra	rtb_no_message	no, go back to bce


sys_trouble_name:
	aci	"sys_trouble: "

" 

	macro	message
	desc9a	&U,&l1
	maclist	off,save
	use	message
	maclist	restore
&U:
	aci	"&1"
	maclist	off,save
	use	main
	maclist	restore
	&end

trouble_messages:
	message	(Page fault while on prds.)

	message	(Fault/interrupt while on prds.)

	message	(Fault in idle process.)

	message	(Fault/interrupt with PTL set.)

	message	(Unrecognized fault.)

	message	(Unexpected fault.)

	message	(Execute fault by operator.)

	message	(Out-of-Segment-Bounds on prds.)

	message	(Fault while in masked environment.)	

	message	(Fault while in bound_interceptors.)

	message	(Ring 0 derail.)

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	The following code enters bce by placing the two
"	absolute mode instructions needed to enter bce
"	into the fault vector slot for the derail fault.
"	NOTE: bp must be preserved  across call to bce since
"	we use it to restore pointer registers upon return.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

rtb_no_message:
	eppbb	fault_vector$+0	bb -> fault vector segment
	ldaq	bb|2*FAULT_NO_LUF+fv.fpair
	staq	lp|save_lockup_fault  save SCU/TRA
	absa	ignore_data	abs addr in 0-23
	als	6		abs addr in 0-17 of Areg
	eaq	0,au		abs addr in 0-17 of Qreg
	oraq	ignore_scu_rcu	replace lockup fault vector
	staq	bb|2*FAULT_NO_LUF+fv.fpair

	szn	scs$processor	all CPU's stopped?
	tnz	*-1		if not, wait here

	lda	4,du		wait for operator's console output to finish
	odd
	sba	1,dl		to allow I/O to drain off
	tnz	*-1		..

" 

" Here is the channel masking code.

	epp0	iom_data$
	eax1	pr0|iom_data.per_device
	lxl0	pr0|iom_data.n_devices
mask.next_device:
	lda	pr0|per_device.flags,x1
	cana	per_device.in_use,du
	tze	mask.skip_device		" not in use now.

	ldq	pr0|per_device.iom,x1	" which iom?
	mpy	per_iom_size,dl		 
	eax2	-per_iom_size+iom_data.per_iom,ql " pr0|per_iom.XXX,x2 
	ldq	pr0|per_device.iom,x1
	mpy	iom_mailbox_size,dl		" address iom mbx
	epp1	iom_mailbox$+iom_mailbox_seg.iom_mailbox-iom_mailbox_size,ql
				          " pr1|mailbox

	ldq	pr0|per_device.channel,x1
	cmpq	=o10,dl			" it has to be bigger than this
	tmi	mask.skip_device		" overhead

	qls	27			" channel position
	oraq	MASK_PCW
	staq	pr1|connect.pcw
	ldq	pr0|per_iom.connect_lpw,x2	" take template PCW
	stq	pr1|connect.lpw		" set up for real
	lda	50,dl
	cioc	pr0|per_iom.cow,x2		" BANG
	odd	
mask.connect_loop:
	cmpq	pr1|connect.lpw		" connect taken yet?
	tnz	mask.skip_device		" nope, wait it out.
	sba	1,dl
	tnz	mask.connect_loop		" keep waiting

mask.skip_device:
	eax1	per_device_size,x1		" next device
	sbx0	1,du			" how many done?
	tnz	mask.next_device		" not all

" 
	

		

	ldaq	bb|2*FAULT_NO_DRL+fv.fpair  grab SCU-TRA pair from fault vector
	staq	lp|save_derail_fault
	ldaq	toehold$+2*TOE_HOLD_MULTICS_ENTRY pick up code to enter bce
	staq	bb|2*FAULT_NO_DRL+fv.fpair  set it in fault vector

drl:	drl	0		****** bce is entered here ******

	szn	scs$connect_lock	did we enter through pmut call?
	tze	drl		if not, cannot restart

	ldac	scs$trouble_flags	get and clear trouble flags
	sta	scs$bos_restart_flags  set for restarting CPU's

	ldaq	lp|save_derail_fault
	staq	bb|2*FAULT_NO_DRL+fv.fpair  ..
	ldaq	lp|save_lockup_fault  restore lockup faults
	staq	bb|2*FAULT_NO_LUF+fv.fpair  ..

	tsx0	broadcast		send trouble connects to start CPU's

	tra	restart		restart the bootload CPU

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	BROADCAST - Send system trouble connects to all other
"		processors.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

broadcast:
	ldq	hbound_processor_data,dl	initialize the Q with maximum configurable CPUs
broadcast_loop:
	cmpq	prds$processor_tag	test for ourselves
	tze	broadcast_next	don't hit ourselves
	lda	scs$processor_data,ql  get processor data for this CPU
	cana	processor_data.online,du  is it configured?
	tze	broadcast_next	if not, don't hit it

	cioc	scs$cow_ptrs,ql*	Zap

broadcast_next:
	sbq	1,dl		step to next CPU
	tpl	broadcast_loop	if more, get the others
	tra	0,0		return to caller

"


	maclist 	off
	include	make_data_macros
	include	iom_word_macros
	maclist	on

	make_pcw	MASK_PCW,0,0,0,record,terminate,0,0,mask

" 

	use	internal_static
	join	/link/internal_static

	even
save_lockup_fault:
	bss	,2		place to save lockup fault SCU and TRA

save_derail_fault:
	bss	,2		place to save derail fault SCU and TRA



" 

	include	scs

	include	flagbox

	include	sys_trouble_codes

	include	fault_vector

	include	toe_hold

	include	iom_data

	equ	connect.pcw,connect_channel*channel_mailbox_size+channel_mailbox.scw
	equ	connect.lpw,connect_channel*channel_mailbox_size+channel_mailbox.lpw


" 

" BEGIN MESSAGE DOCUMENTATION
"
" Message:
" sys_trouble: Page fault while on prds.
"
" S:	$crash
"
" T:	$run
"
" M:	$err
"
" A:	$recov
"
"
" Message:
" sys_trouble: Fault/interrupt while on prds.
"
" S:	$crash
"
" T:	$run
"
" M:	$err
"
" A:	$recov
"
"
" Message:
" sys_trouble: Fault in idle process.
"
" S:	$crash
"
" T:	$run
"
" M:	$err
"
" A:	$recov
"
"
" Message:
" sys_trouble: Fault/interrupt with ptl set.
"
" S:	$crash
"
" T:	$run
"
" M:	$err
"
" A:	$recov
"
"
" Message:
" sys_trouble: Unrecognized fault.
"
" S:	$crash
"
" T:	$run
"
" M:	Unexpected or unrecognized fault subcondition.
"	Probable hardware malfunction.
"
" A:	$contact
"
"
" Message:
" sys_trouble: Unexpected fault.
"
" S:	$crash
"
" T:	$init
"
" M:	$err
"
" A:	$recov
"
"
" Message:
" sys_trouble: Execute fault by operator.
"
" S:	$crash
"
" T:	$run
"
" M:	Operator depressed execute pushbutton on processor.
"
" A:	$recov
"
"
" Message:
" sys_trouble:  Out-of-Segment-Bounds on prds.
"
" S:	$crash
"
" T:	$run
"
" M:	While running with the prds as a stack, an attempt was
"	made to reference beyond the end of the prds.  The likely
"	cause was stack overflow, due either to a recursive loop
"	in the procedures running on the prds or insufficient
"	space allocated for the prds.  If the latter, the size of
"	the prds should be increased by means of the TBLS Configuration
"	Card.
"
" A:	$recover
"
"
" Message:
" sys_trouble: Interrupts Masked in User Ring.
"
" S:	$crash
"
" T:	$run
"
" M:	During processing of a fault, it was noticed that interrupts
"	were masked in user-ring, an invalid condition. This is a
"	debug trap crash, enabled by the hidden tuning parameter
"	trap_invalid_masked.
"
" A:	Contact the Multics System Development staff.
"
"
" Message:
" sys_trouble: Fault in bound_interceptors.
"
" S:	$crash
"
" T:	$run
"
" M:	A fault occured while handling another fault.
"
" A:	$recov
"
"
" Message:
" sys_trouble: Ring 0 derail. {MESSAGE}
"
" S:	$crash
"
" T:	$run
"
" M:	A supervisor software module discovered an untenable situation, and
"	crashed the system by executing a derail (DRL) instruction.
"	If MESSAGE is also present, it will be of the form:
"         "module: explanation", and further details can be found in
"	this documentation in the description of "module".
"
" A:	$recov
"
" END MESSAGE DOCUMENTATION



	end




		    wired_fim.alm                   11/11/89  1139.5rew 11/11/89  0801.2      138933



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Bull Inc., 1987                *
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1984 *
" *                                                         *
" * Copyright (c) 1972 by Massachusetts Institute of        *
" * Technology and Honeywell Information Systems, Inc.      *
" *                                                         *
" ***********************************************************


" HISTORY COMMENTS:
"  1) change(87-03-02,Lippard), approve(87-04-06,MCR7658),
"     audit(87-06-10,Fawcett), install(87-07-17,MR12.1-1043):
"     Modified to complete cam_wait race fix.  (This fix from SGH (UNCA).)
"                                                      END HISTORY COMMENTS


" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	wired_fim
"
"	Last Modified: (Date and Reason)
"	Written 1/70 S.Webber
"	Modified by S.Webber 01/01/72 for followon
"	Modified by S.Webber 10/15/73 to add SPL/LPL code for all faults
"	Modified by S.Webber 12/18/73 to remove page fault code
"	Modified by Noel I. Morris 2/11/76 for new connect faults
"	Modified by Mike Grady 6/79 to do stop on prds
"	Modified by J. A. Bush 3/80 to store execute fault time in machine conditions
"	Modified by J. Bongiovanni 1/81 for fault_counters
"	Modified by J. Bongiovanni 2/81 for fast connect code,
"		traffic control race condition
"	Modified by J. A. Bush 6/3/81 to save fault time for unexpected faults
"	Modified by J. Bongiovanni 1/05/82 to fix CPU start wait bug
"	Modified by R. Coppola 10/12/83 to meter faults on a per-cpu basis
"         Modified 84-03-13 BIM (after Steve Harris) to close cam_wait race
"
"	The following entries exist within this procedure:
"
"	connect_handler	handles inter-processor communication
"
"	pre_empt_return	return from pxss after pre-empt
"
"	ignore		certain faults are ignored here
"
"	timer_runout	timer runout faults are mapped into
"			pre-empts
"
"	unexp_fault	unexpected faults come here during
"			system initialization
"
"	xec_fault		execute faults will cause return to BOS
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


	name	wired_fim

" 

	include	pxss_page_stack

" 

	segdef	prs,scuinfo
	segdef	int_scuinfo
	segdef	trouble_prs,trouble_scuinfo
	segdef	ignore_scuinfo,ignore_pl
	segdef	my_linkage_ptr

	segdef	pre_empt_return
	segdef	ignore
	segdef	timer_runout
	segdef	connect_handler
	segdef	unexp_fault
	segdef	xec_fault




" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	The following variables are set up during initialization.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	even
prs:	bss	,2
scuinfo:	bss	,2

int_scuinfo:
	bss	,2

trouble_prs:
	bss	,2
trouble_scuinfo:
	bss	,2
ignore_pl:
	bss	,2
ignore_scuinfo:
	bss	,2

my_linkage_ptr:
	bss	,2

"

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	CONNECT_HANDLER -- Handle Connect Faults.
"
"	Connect faults may be sent for the following reasons:
"	1.	To cause a system trouble abort.
"	2.	To clear cache and associative memory.
"		(the clearing has already been done by
"		 prds$fast_connect_code by the time we get here)
"	3.	To wait for a new CPU to start up.
"	4.	To cause a processor to delete itself.
"	5.	To cause a process pre-empt.
"	6.	To cause a process stop.
"	7.	To cause an IPS event to be signalled.
"
"
"	By the time this entry has been called, the fast connect
"	in the prds has been called.  This code has done the
"	following:
"
"	1. 	If scs$fast_cam_pending was set for this cpu,
"		AND this is not a cam_wait exchange,
"		xed  scs$cam_pair
"		stz  scs$fast_cam_pending + <processor tag>
"	2.	Added 1 to the counter
"		wired_hardcore_data$fault_counters + <FAULT_NO_CON>
"
"         In the cam_wait case the clearing of the fast_cam_pending
"	must await our being done with the pds, since it may be
"	under eviction to move it to another scu. Clearing fast_cam_pending
"	informs cam_cache that we are in fact looping on scs$cam_wait,
"	AND NOTHING ELSE.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	even
connect_handler:
	spri	prs,*		save prs
	eppbp	prs,*		bp -> place for machine conditions
	sreg	bp|mc.regs	save regs
	spl	bp|mc.eis_info	save EIS ptrs and lgths
	epplp	my_linkage_ptr,*	set up linkage ptr

	tsx0	fim_util$v_time_init  start virtual time metering

	lda	scs$sys_trouble_pending  system trouble?
	cana	prds$processor_pattern  for this CPU?
	tnz	sys_trouble$sys_trouble  go handle it

	tsx0	fim_util$check_mct	go save M.C.s and hregs if trace is on
	nop			" return ic +1
	tsx0	fim_util$reset_mode_reg  start up hist regs again

	lda	prds$processor_pattern	see if we're waiting for
	cana	scs$cam_wait		for all cams to clear
	tnz	cam_wait			yes--go do it

	cana	scs$processor_start_wait  waiting for CPU to start up?
	tnz	start_wait	if so, go wait

	lxl1	prds$processor_tag	CPU tag in X1
	lda	scs$processor_data,1  look at CPU flags
	cana	processor_data.delete_cpu,du  is this CPU to delete itself?
	tnz	delete_cpu	if so, cause a pre-emption

more:	epplb	pds$apt_ptr,*	lb -> APT entry for this process
	lda	lb|apte.flags	look at process flags
	cana	apte.stop_pending,du  stop?
	tnz	stop		go handle stop

	cana	apte.pre_empt_pending,du  pre-empt?
	tnz	pre_empt		go handle pre-empt

	lda	lb|apte.ips_message	IPS message?
	tnz	ips		go handle IPS
	tra	exit		drop through to exit

"

ralr_set_1:
	lda	1,dl		cannot handle fault now
	sta	pds$alarm_ring	defer it until later

	odd
exit:
	tsx0	fim_util$v_time_calc  calculate virtual time

exit_1:
	lpl	bp|mc.eis_info	restore EIS ptrs and lths
	lra	pds$alarm_ring	FIM may have reset this
	lreg	bp|mc.regs	restore regs
	lpri	bp|mc.prs		and prs
	rcu	scuinfo,*		good-bye



" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	IGNORE -- several faults are ignored by directing them
"		to this entry.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

ignore:
	spl	ignore_pl,*         make EIS happy
	lpl	ignore_pl,*
	rcu	ignore_scuinfo,*	restore the machine conditions



" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	XEC_FAULT and UNEXP_FAULT -- These entries cause
"		the system to abort.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

xec_fault:
	spri	trouble_prs,*	save prs
	eppbp	trouble_prs,*	bp -> machine conditions
	sreg	bp|mc.regs	save regs
	spl	bp|mc.eis_info	save EIS ptrs and lths
	epplp	my_linkage_ptr,*	establish linkage ptr
	rccl	sys_info$clock_,*	read the clock
	staq	bp|mc.fault_time	and save in machine conditions

	lca	trbl_exec_flt,dl	set sys trouble indicator
	sta	scs$sys_trouble_pending  ..
	lda	pds$processid	save our process ID
	stac	scs$trouble_processid if we're the first
	tra	sys_trouble$sys_trouble  map into sys_trouble code


unexp_fault:
	spri	trouble_prs,*	save prs
	eppbp	trouble_prs,*	bp -> machine conditions
	sreg	bp|mc.regs	save regs
	spl	bp|mc.eis_info	save EIS ptrs and lths
	epplp	my_linkage_ptr,*	establish linkage ptr
	rccl	sys_info$clock_,*	read the clock
	staq	bp|mc.fault_time	and save in machine conditions

	lca	trbl_unexp_flt,dl	set sys trouble indicator
	sta	scs$sys_trouble_pending  ..
	lda	pds$processid	save our process ID
	stac	scs$trouble_processid if we're the first
	tra	sys_trouble$sys_trouble  map into sys_trouble code

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	TIMER_RUNOUT - Timer runouts are mapped into pre-empts.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	even
timer_runout:
	spri	prs,*		save prs
	eppbp	prs,*		bp -> machine conditions

	sreg	bp|mc.regs	save regs
	spl	bp|mc.eis_info	save EIS ptrs and lths
	epplp	my_linkage_ptr,*	establish linkage ptr

	tsx0	fim_util$v_time_init  start virtual time meter

	tsx0	fim_util$check_mct	go save M.Cs ad hregs if trace is on
	nop			" return ic +1
	tsx0	fim_util$reset_mode_reg  start up hist regs
	lda	prds$processor_tag	get cpu num in A for index
	xec	fault_ctr_table,al	LB => per-cpu flt ctr array
	aos	lb|0+FAULT_NO_TRO
	
cause_pre_empt:
	epplb	pds$apt_ptr,*	lb -> APT entry for this process
	ldx0	apte.pre_empt_pending,du  get pre-empt indicator flag
	orsx0	lb|apte.flags	set pre-empt flag

	tra	pre_empt		join common code

fault_ctr_table: 
	epplb	wired_hardcore_data$cpu_a_flt_ctr_array
	epplb	wired_hardcore_data$cpu_b_flt_ctr_array
	epplb	wired_hardcore_data$cpu_c_flt_ctr_array
	epplb	wired_hardcore_data$cpu_d_flt_ctr_array
	epplb	wired_hardcore_data$cpu_e_flt_ctr_array
	epplb	wired_hardcore_data$cpu_f_flt_ctr_array
	epplb	wired_hardcore_data$cpu_g_flt_ctr_array
	epplb	wired_hardcore_data$cpu_h_flt_ctr_array


" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	DELETE_CPU - Cause a pre-empt to stop CPU.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

delete_cpu:
	lca	1,dl		all ones in A
	era	prds$processor_pattern  get bit for CPU to be deleted
	ansa	scs$connect_lock	undo the connect lock

	tra	cause_pre_empt	now, cause a pre-empt to take place

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	CAM_WAIT -- Wait for all cpus to clear, and originator to
"		  give "Go"
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

cam_wait: 
	eppsb	prds$		push a frame onto the prds
	ldx7	push		..
	tsx0	fim_util$push_stack_32  ..

	eppap	notify_regs	ap -> place to copy conditions
	tsx0	fim_util$copy_mc	copy the conditions into stack

" NB: once scs$fast_cam_pending is cleared by this processor it must
" not reference anything that the originator of the cam_wait condition
" might be in the process of moving -- see evict_page.alm.  This includes
" pds and prds pages which may exist outside of bootload memory.

	tsx0	fim_util$set_mask	must uninhibit to prevent lockup

	lda	prds$processor_pattern  get bit for this CPU

	xed	scs$cam_pair	clear AM (and maybe cache?)
	lxl7	prds$processor_tag
	stz	scs$fast_cam_pending,x7 signal that we are out of the way

	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	cana	scs$cam_wait	still waiting?
	tze	*+4		if not, exit loop
	llr	72
	llr	72
	tra	*-4		if so, wait more

	tsx0	fim_util$restore_mask  can inhibit again
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

	cams	0		now, clear A.M.'s
	camp	0		a second time

	eppap	prs,*		prepare to copy machine conditions back
	tsx0	fim_util$copy_mc	..

	eppap	sp|-32		get original stack end pointer
	spriap	sb|stack_header.stack_end_ptr  pop our stack frame
	tra	more		and leave

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	START_WAIT - Wait until new CPU has started up.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

start_wait:
	lca	1,dl		all ones in A
	era	prds$processor_pattern  turn off bit for this CPU
	ansa	scs$processor_start_wait  check ourselves off

	eppsb	prds$		push a frame onto the prds
	ldx7	push		..
	tsx0	fim_util$push_stack_32  ..

	eppap	notify_regs	ap -> place to copy conditions
	tsx0	fim_util$copy_mc	copy the conditions into stack

	tsx0	fim_util$set_mask	uninhibit to prevent lockups
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	szn	scs$connect_lock	test connect lock
	tze	*+4		wait until it is cleared
	llr	72
	llr	72
	tra	*-4

	tsx0	fim_util$restore_mask  can inhibit again
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

	eppap	prs,*		prepare to copy machine conditions back
	tsx0	fim_util$copy_mc	..

	eppap	sp|-32		get original stack end pointer
	spriap	sb|stack_header.stack_end_ptr  pop our stack frame
	tra	exit		all finished waiting

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	PRE_EMPT - Handle process pre-emptions.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

pre_empt:
	tsx0	ring_test		ring 0 & not idle?
	tra	ralr_set_1	if so, delay this for later

	eppap	pds$page_fault_data	copy machine conditions
	tsx0	fim_util$copy_mc	..

	tsx0	fim_util$set_mask	mask system controller

	eppsb	prds$		establish stack frame on the prds
	ldx7	push		..
	tsx0	fim_util$push_stack	..
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	tra	pxss$pre_empt	go to pxss



" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	PRE_EMPT_RETURN -- Transferred to when pre_empt has been processed
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

pre_empt_return:
	epplp	my_linkage_ptr,*
	eppbp	pds$page_fault_data	get pointer to machine conditions

	tsx0	fim_util$restore_mask  restore old controller mask
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

	ldaq	sb|stack_header.stack_begin_ptr  restore prds to virgin state
	staq	sb|stack_header.stack_end_ptr  ..

	odd
	tsx0	fim_util$v_time_calc  compute virtual time

	lpl	bp|mc.eis_info	restore EIS ptrs and lths
	lreg	bp|mc.regs	restore regs
	lpri	bp|mc.prs		and prs
	rcu	int_scuinfo,*	bye-bye

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	STOP - Handle process stop
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

stop:
	tsx0	ring_test		ring 0 & not idle?
	tra	ralr_set_1	if so, delay handling this

	eppap	pds$page_fault_data	copy machine conditions
	tsx0	fim_util$copy_mc	..

	tsx0	fim_util$set_mask	mask system controller

	eppsb	prds$		Establish stack on prds
	ldx7	push		..
	tsx0	fim_util$push_stack	..
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	tra	pxss$force_stop	go to pxss

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	IPS - Handle Interprocess Signals
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

ips:
	tsx0	ring_test		ring 0 & not idle?
	tra	ralr_set_1	we'll hear about this later

	eppap	pds$signal_data	copy the machine conditions
	tsx0	fim_util$copy_mc	..

	eppsb	pds$stack_0_ptr,*	Establish pageable stack.
	ldx7	push		..
	tsx0	fim_util$push_stack	..

	tsx0	fim_util$v_time_calc  compute virtual time
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	call	proc_int_handler$proc_int_handler

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	eppap	prs,*		copy SCU data only back
	mlr	(pr),(pr)		..
	desc9a	bp|mc.scu,8*4
	desc9a	ap|mc.scu,8*4

	sprisp	sb|stack_header.stack_end_ptr  release our stack frame
	tra	exit_1		all finished

" 

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	RING_TEST - internal subroutine to see if process
"		is in ring 0 and not an idle process
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

ring_test:
	lda	bp|mc.scu.ppr.prr_word  get PRR
	ana	scu.ppr.prr_mask,du ..
	tnz	1,0		if outer ring, take second return

	lda	lb|apte.flags	get process flags
	cana	apte.idle,du	idle process?
	tze	0,0		if not, take first return

	epaq	sp|0		get stack pointer in AQ
	eax7	0,au		stack segno in X7
	cmpx7	trouble_scuinfo	is it prds?
	tze	0,0		if so, go away
	tra	1,0		if not, take second return

" 

push:	push


	include	mc

" 

	include	stack_header

" 

	include	scs

	include	sys_trouble_codes

" 

	include	apte
"
	include	fault_vector



	

	end






		    bull_copyright_notice.txt       08/30/05  1008.4r   08/30/05  1007.3    00020025

                                          -----------------------------------------------------------


Historical Background

This edition of the Multics software materials and documentation is provided and donated
to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. 
as a contribution to computer science knowledge.  
This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology,
Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull
and Bull HN Information Systems Inc. to the development of this operating system. 
Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970),
renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership
of Professor Fernando Jose Corbato.Users consider that Multics provided the best software architecture for 
managing computer hardware properly and for executing programs. Many subsequent operating systems
incorporated Multics principles.
Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., 
as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. .

                                          -----------------------------------------------------------

Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without
fee is hereby granted,provided that the below copyright notice and historical background appear in all copies
and that both the copyright notice and historical background and this permission notice appear in supporting
documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining
to distribution of the programs without specific prior written permission.
    Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc.
    Copyright 2006 by Bull HN Information Systems Inc.
    Copyright 2006 by Bull SAS
    All Rights Reserved
