



		    absadr.alm                      11/11/89  1106.2rew 11/11/89  0803.8       28269



" ***********************************************************
" *                                                         *
" * 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.      *
" *                                                         *
" ***********************************************************

" ABSADR - Compute Absolute Address from ITS Pair.
"	Written 06/02/67 - Noel I. Morris
"	Other modifications made through the years by various Multicians who
"	   curiously prefer the cloak of anonymity.
"	Modified 03/21/81, W. Olin Sibert, for ADP conversion



" Calling Sequence:
"	absolute_address = absadr (pointer, error)
"
" Where:
"	pointer - its pointer.
"	absolute_address - answer as fixed bin (24) integer.
"	error - error code.
"
" Errors:
"	1.	Bound fault.
"	2.	Directed Fault in SDW.
"	3.	Directed Fault in PTW.
"



	name	absadr
	entry	absadr


	tempd	sdw_save,temp
	temp	word_offset,temp1



	include	sdw
	include	ptw


" 


absadr:	push
	eppbp	ap|2,*		pick up pointer to its pair
	epaq	bp|0,*		get info into aq-reg
	anq	-1,du
	stq	word_offset	save word offset of effective pointer
	ana	-1,du
	als	1		* 2
	eax0	0,au		seg no * 2 to X0

	epaq	abs_seg$+0
	als	1
	eax1	0,au
	ldaq	dseg$+0,x1	pick up previous SDW for absolute segment
	staq	sdw_save		and stash it away

	ldaq	dseg$+0,x0	pick up SDW for segment
	staq	temp		save it
	cana	sdw.valid,dl	test for directed fault
	tze	error_2		..

	qrl	sdw.bound_shift	" Check against the SDW bound
	anq	sdw.bound_mask,dl
	qls	18+4		" Convert to word count in QU
	adlq	=o17,du		" And add 15 to get word count
	cmpq	word_offset	compare against word offset
	tnc	error_1		test for bound fault	

	ldaq	temp		restore SDW to AQ
	canq	sdw.unpaged,dl	paged ?
	tnz	addr		no

	lda	word_offset	get address
	arl	10		take address mod (page size - 1024)
	eax6	0,au		put page number in x6
	lda	temp		get page table addr from sdw
	als	18-sdw.add_shift	right justify it in au
	ana	=o17,du		find its offset from a 0 mod 16 word addr
	sta	temp1		save this number a bit
	adx6	temp1		x6 now has addr of desired page table word
"				as an offset from a 0 mod 16 boundary

	ldaq	temp
	ana	=o777777607777	make address field 0 mod 16 for unpaged sdw
	orq	sdw.unpaged,dl	make it unpaged
	staq	dseg$+0,x1	store in SDW for absolute segment
	cams	0		clear assoc. memory
	lda	abs_seg$+0,x6	pick up PTW
	cana	ptw.valid,dl		test for directed fault
	tze	error_3		..


addr:
	absa	bp|0,*		generate absolute address
	arl	12
	sta	ap|6,*		return absolute address

	ldq	0,dl		make error code zero
end:
	stq	ap|4,*		return error code
	ldaq	sdw_save		restore previous SDW
	staq	dseg$+0,x1	..
	cams	0		reset associative memory

	return



error_1:
	ldq	1,dl		bound fault
	tra	end		..

error_2:
	ldq	2,dl		directed fault in SDW
	tra	end		..

error_3:
	ldq	3,dl		directed fault in PTW
	tra	end		..




	end
   



		    parity_check.alm                11/11/89  1106.2r   11/11/89  0803.8       18081



" ***********************************************************
" *                                                         *
" * 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.      *
" *                                                         *
" ***********************************************************
	name	parity_check

	entry	parity_check
	entry	set_parity_mask
	entry	reset_parity_mask

"	Last Modified by RBSnyder 02/14/73 for follow-on

"
"	call parity_check(loc, word, check)
"
"	 loc pointer	pointer to parity cell
"	word bit(36)	contents of cell indicating parity
"	check fixed bin	= 0 if no parity
"
"
"	This routine is called to validate the existence of a parity error
"	by re-accessing the word in question.
"	It is used by the software to verify that the
"	condition was in fact a memory parity error.
"
"
"
"
"	call set_parity_mask
"
"	This entry is used to set the parity mask indicator in
"	the caller's indicators.
"
"
"	call reset_parity_mask
"
"	This entry is the reverse of the one above
"

	include	mc
"

parity_check:
	ldi	scu.ir.parm,dl	Set mask
	eppbp	ap|2,*		Pick up pointer to cell
	lda	bp|0,*		Read from cell
	sta	ap|4,*		Return contents
	sti	ap|6,*		Store indicators into return arg
	lda	scu.ir.par,dl	Pick up mask
	ansa	ap|6,*		If error occured, will be non-zero
	short_return

set_parity_mask:
	sti	sp|0		store the current indicators
	lda	scu.ir.parm,dl	Pick up masking bit
	orsa	sp|0		store into stored indicators
	ldi	sp|0		reload indicators
	short_return

reset_parity_mask:
	sti	sp|0		save current indicators
	lca	scu.ir.parm+1,dl	Form 1-s complement of mask
	ansa	sp|0		and delete the bit
	ldi	sp|0		get new indicators
	short_return

	end	parity_check	
   



		    privileged_mode_ut.alm          11/11/89  1106.2rew 11/11/89  0804.2      304461



" ***********************************************************
" *                                                         *
" * 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.      *
" *                                                         *
" ***********************************************************

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	privileged_mode_ut
"
"	This segment contains master mode utility routines
"	required by hardcore ring procedures in order to execute
"	6180 instructions which can only be executed in
"	privileged mode.
"
"	Revised for New File System 1/69 SHW
"
"	Converted for the follow-on by Craig Jensen on 6/27/72.
"	Code for 6180 cache added 2/74 by B. Greenberg
"	Modified 4/8/74 by S.H.Webber to remove checks and change lockptl meter code
"	Lock PTL code and cam code moved to page, 6/19/74 BSG
"	Modified on 01/06/75 at 21:57:15 by R F Mabee.  Fixed SDW alignment assumptions.
"	Modified 6/16/75 by R.F.Mabee.  Fixed parity_error reporting bug per BSG.
"	Modified 2/18/76 by S. Webber for new reconfiguration
"	Modified 7/18/78 by J. A. Bush for new smic_port entry
"         Modified 5/11/79 by Mike Grady for stack 0 sharing.
"	Modified 3/11/80 by Mike Grady to make mask restores more robust.
"	Modified 5/30/80 by J. A. Bush to wire (and unwire) number of pages
"	 in wired_hardcore_data$wire_pages
"	Modified 1/08/81 by J. Bongiovanni to account for wired pages 
"	Modified 2/10/81 by J. A. Bush for the read_id_prom entry
"	Modified 1/05/82 by J. Bongiovanni to make check_parity_for_use
"	 faster
"	Modified 2/8/82  by J. Bongiovanni to set ralr to 1 on mask to
"	 sys_level (optionally), add entry read_mask
"	Modified 6/23/82 by J. A. Bush to add the clear_cache entry
"         Modified 7/82 BIM to merge in ldt and ldbr from privileged_mode_init.
"                 for the 10 instructions here that program could be deleted.
"         Modified 8/82 JJB for scs footprints to identify crash process.
"	Modified 1/83 JJB to set lockup fault vector to ignore faults absolutely
"	Modified 6/83 ENK for load_mode_reg
"	Modified 8/83 KPL for bootload Multics shutdown, also for camp entry
"	Modified 10/83 KPL for checking sst_boundary for unpaged
"	Modified 1/84 KPL for special_bce_return
"	Modified 5/84 KPL for cam_both
"         Modified 1985-03-11, BIM: clear mem before checking for freecore
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


" HISTORY COMMENTS:
"  1) change(88-07-27,Farley), approve(88-10-05,MCR7968),
"     audit(88-10-10,Beattie), install(88-10-14,MR12.2-1166):
"     Added new entry check_for_mem_overlap to check for memory addressing
"     overlap conditions, which cannot be detected by simply reading the SCU
"     configuration.
"                                                      END HISTORY COMMENTS


	name	privileged_mode_ut

	entry	bce
	entry	bce_and_return
	entry	cam
	entry	cam_both
	entry	cam_cache
	entry	clear_cache
	entry	check_for_mem_overlap
	entry	check_parity_for_use,check_parity_for_add
	entry	cioc
	entry	ldt
	entry	ldbr
	entry	load_mode_reg
	entry	lock_ptl
	entry	lrar
	entry	read_id_prom
	entry	read_mask
	entry	rscr
	entry	rsw
	entry	set_mask
	entry	smcm
	entry	smic
	entry	smic_port
	entry	special_bce_return
	entry	sscr
	entry	swap_sdw
	entry	camp
	entry	trace_rsw
	entry	unlock_ptl
	entry	unwire_unmask
	entry	wire_and_mask


	even
channel_mask_set:			" used to retain current channel mask
	oct	000000000017,000000000017
	temp8	rip_str1,rip_str2
	tempd	maskd,save_sdw,save_sdw1
	temp	old_low_data,new_low_data,old_high_data,new_high_data
	temp	indicators,save_indicators,new_value,addr,indicators_no_par,call_type
	temp	lock_sw,temp,rsw_xec,tally_wd

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	read_mask is used to obtain the current value of the interrupt
"	mask on the running CPU
"
"	The calling sequence is
"
"		call privileged_mode_ut$read_mask (mask_pattern)
"
"		where mask_pattern is a fixed bin (71) value
"		into which will be stored the value of the
"		interrupt mask
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

read_mask:
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	lxl1	prds$processor_tag
	lprpab	scs$mask_ptr,1
	xec	scs$read_mask,1
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	staq	ap|2,*
	short_return
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"
"	set_mask  is called from the interrupt interceptor.
"
"	The calling sequence is:
"
"		call privileged_mode_ut$set_mask(mask_pattern,temp)
"
"		where mask_pattern is a fixed bin (71) value which
"		will be loaded into the mask register of the system
"		controller assigned to send interrupts to the
"		processor on which this procedure is executing,
"
"		and temp is a fixed bin (71) item which the mask register
"		at the time of entry will be loaded into.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

set_mask:
	push

" Note that the processor may be lost between reading and setting the mask.

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	lxl1	prds$processor_tag
	lprpab	scs$mask_ptr,1
	xec	scs$read_mask,1	read mask
	staq	maskd		save temporarily

	ldaq	ap|2,*		get new mask
	oraq	channel_mask_set	forget old channel mask
	anaq	scs$open_level	correct mask
	lxl1	prds$processor_tag
	lprpab	scs$mask_ptr,1
	xec	scs$set_mask,1	set new mask
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	szn	wired_hardcore_data$trap_invalid_masked are we checking mask
	tze	not_sys_level	no
	cmpaq	scs$sys_level	masking to system level
	tnz	not_sys_level	no
	lda	1,dl		set ring alarm
	sta	pds$alarm_ring
	lra	pds$alarm_ring

not_sys_level:
	ldaq	maskd		get old mask
	ldx7	ap|0		get arg count
	cmpx7	2*2,du		two args?
	tmi	*+2		if not, don't return old mask
	staq	ap|4,*		return old mask

	return

" 
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	lock_ptl	used to lock page table lock and mask.
"		Call is:
"
"		call privileged_mode_ut$lock_ptl(oldmask,ptwp)
"
"		dcl oldmask fixed bin (71)
"		dcl ptwp ptr
"
"	wire_and_mask	used to wire stack and mask
"		same calling seq as lock_ptl
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	link	sst_link,sst$
	link	abs_seg_link,abs_seg$
	link	abs_seg_link1,abs_seg1$
	link	prds_link,prds$

wire_and_mask:
	eax2	0		set sw not to lock
	tra	lptl1
lock_ptl:
	eax2	1		set sw to lock

lptl1:	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	lxl1	prds$processor_tag
	lprpab	scs$mask_ptr,1
	xec	scs$read_mask,1	read current mask
	staq	ap|2,*		return current mask

	lxl1	prds$processor_tag
	lprpab	scs$mask_ptr,1
	ldaq	scs$sys_level	mask down to sys level
	xec	scs$set_mask,1	set the new mask
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

"	set ring-alarm to 1 if we're checking for masked in user-ring

	szn	wired_hardcore_data$trap_invalid_masked
	tze	not_checking
	lda	1,dl
	sta	pds$alarm_ring
	lra	pds$alarm_ring
not_checking:

"
"	now wire down <n> pages of the stack (determined from wired_hardcore_data$wire_pages)
"
	eppbb	sst$		get pointer into the SST
	spribb	ap|4,*		arg -> <sst>|0 if we don't wire
	epaq	sp|0		find the stack's segment number
	eax0	0,au		get segno in x0
	cmpx0	lp|prds_link	are we running on prds?
	tze	no_wire		yes, skip wiring

	als	1		Double seg. no. since SDW's are 72 bits long.
	eax3	0,au		copy sdw index
	ldaq	dseg$,au
	arl	sdw.add_shift	Get abs addr of stack's page table.

	cmpa	unpaged_page_tables$0+upt.sst_last_loc	Page table not in sst
	tpnz	no_wire			=> unpaged seg
	sbla	unpaged_page_tables$0+upt.sst_absloc	Get offset of stack's 
	tmi	no_wire			page table in SST.

	eppbp	bb|0,al		bp -> page table
	lda	ptw.wired,dl	get wired bit for page 0
	cana	bp|0		is it already wired?
	tnz	already_wired_and_masked
	orsa	bp|0		make it wired now
	aos	bb|sst.wired	adjust count of wired pages
	
	eaq	sp|0		get offset in stack of current frame
	qrl	18+10		get page number in q
	eppbp	bp|0,ql		bp -> ptw
	spribp	ap|4,*		return pointer to caller

	lxl4	wired_hardcore_data$wire_pages get number of pages to wire
bound_lp:
	epplb	sp|0		copy stack ptr
	eaq	0,4		copy pages to wire to qu
	qls	10		multiply by 1024 to get number of words
	awd	lb|0,qu		add to lb word offset
	epaq	lb|0		copy ptr to aq
	lls	18		word offset in al
	sbla	1,dl
	arl	4		divide by 16
	ldq	dseg$+1,3		load sdw bound in q
	qls	15		shift out old bounds
	lls	18+3		a reg now contains new sdw bounds + rest of sdw 2nd word
	cmpa	dseg$+1,3		is the final address out of bounds?
	tmi	bound_ok		no, wire whats in x4
	eax4	-1,4		yes, subtract 1 from pages to wire
	tra	bound_lp		and go try again
bound_ok:
	eaa	0,4		get number of pages wired
	ana	=o77,du		can't be more than 63 pages
	arl	12		position so number will be in bits 24 to 29
	orsa	ap|2,*		set in unused area of mask
	epbplb	sp|0		get ptr to stack base
	szn	lb|0		touch page 0 to make sure its in core
	eax0	0		initialize ptw index
	epplb	sp|0		copy our stack ptr
	lda	ptw.wired,dl	set wired bit in a
lk_lp1:
	cana	bp|0,0		is page already wired
	tnz	lk_lp1_wired	yes
	orsa	bp|0,0		wire page
	aos	bb|sst.wired	bump count of wired pages
lk_lp1_wired: 
	szn	lb|0		touch it to get it in core
	eax0	1,0		increment ptw index
	adwplb	1024,du		increment stack page address
	eax4	-1,4		decrement pages to wire
	tnz	lk_lp1		wire next one if not done yet

no_wire:	eax2	0,2		see if lock entry
	tnz	device_control$ptl_waitlock
		"contract: 1. I am running in stack frame to which I want to be returned.
		"	 2. Only remaining instruction is "return".
		"	 3. Wired stack, sys masked.
		"	 4. Don't return until ptl locked.

	short_return

already_wired_and_masked:
	lda	=o40,dl		Indicate wired state.
	orsa	ap|2,*		move to arg.
	tra	no_wire

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	unlock_ptl	entry to unlock and unmask after finishing messing with
"		the page control data.
"		Call is:
"
"		call privileged_mode_ut$unlock_ptl(oldmask,ptwp)
"
"		dcl oldmask fixed bin (71)
"		dcl ptwp ptr
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

unlock_ptl:
	tra	page_fault$pmut_unlock_ptl	avoid push, minimal elegance
unwire_unmask:
	ldaq	ap|2,*		pick up mask setting
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	oraq	channel_mask_set	forget old channel mask
	anaq	scs$open_level
	lxl1	prds$processor_tag	get tag for masking
	lprpab	scs$mask_ptr,1
	xec	scs$set_mask,1
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->
"
"	now unwire the pages wired down by lock_ptl
"
	lda	ap|2,*		Get the mask and flag back
	cana	=o40,dl		Was it wired already?
	tnz	.rt		Yes, just exit.
	als	12		position number of pages wired
	ana	=o77,du		allow only 63 pages
	eax4	0,au		copy to x4
	eppbp	ap|4,*		get page table pointer
	eppbp	bp|0,*
	eax0	bp|0		is offset zero?
	tze	.rt		if so, don't unwire
	eax2	0		-(count of pages unwired)
	epaq	sp|0		get ptr to stack for segno
	als	1		times two since SDW's are 72 bits
	lda	dseg$,au		load SDW
	arl	sdw.add_shift	shift address for ptw
	eppbb	sst$		ptw's are in sst
	sbla	bb|sst.ptwbase	offset for page 0 ptw
	eppbb	bb|0,al		bb -> page 0 ptw

	lca	ptw.wired+1,dl	get set to turn off wired bits
	ldq	ptw.wired,dl	and to check wired bits
	canq	bb|0		is page still wired
	tze	ul_p0_unwired	no
	ansa	bb|0		turn off wired bit in page 0
	eax2	-1,2		count page unwired
ul_p0_unwired: 
	
	eax0	0		count ptws

ul_l1:	canq	bp|0,0		is page still wired
	tze	ul_pg_unwired	no
	ansa	bp|0,0		unwire this page
	eax2	-1,2		count page unwired
ul_pg_unwired: 
	eax0	1,0		move on
	eax4	-1,4		decrement	 number of pages wired
	tnz	ul_l1
	eaq	0,2		qu=-(count of pages unwired)
	qrs	18		qr=-(count of pages unwired)
	asq	sst$0+sst.wired	adjust count of wired pages
	
.rt:	short_return

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	cioc is called to connect to any of the active modules on
"	a system controller except a processor.
"
"	The calling sequence is:
"
"		call privileged_mode_ut$cioc(cow)
"
"		where cow is a 36 bit aligned connect operand
"		word.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

cioc:	eppbp	ap|2,*		Issue cioc instruction
	cioc	bp|0,*		at arg1
	short_return

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	LRAR
"
"	Entry to set the ring alarm register.
"	Call is:
"
"	call pmut$lrar (rar_value)
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

lrar:	lra	ap|2,*		load the ring alarm register
	short_return		short and sweet

" 
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"
"
"	Entry to load the mode register
"	Call is:
"
"	call pmut$load_mode_reg;
"
"	called after the caller has altered pds$hfp_exponent_enabled.
"	(this code duplicates pxss at process switch.)
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
load_mode_reg:
	eppab	prds$mode_reg_enabled
	lca	mr.enable_hfp+1,dl		is hex fp enabled for this process?
	ana	prds$mode_reg
	szn	pds$hfp_exponent_enabled
	tze	*+2
	ora	mr.enable_hfp,dl
	sta	prds$mode_reg
	ora	mr.enable_mr+mr.enable_hist,dl  enable mode reg and enable hist regs
	sta	ab|0
	lcpr	ab|0,04
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->
	short_return

" 
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"
"	cam code moved to page by BSG, 6/19/74
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

cam:	tra	page$cam

cam_cache:
	tra	page$cam_cache

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"
"	clear_cache - entry to clear cache by turning cache off and 
"		    then back on. Note that this will work for both
"		    the L68 and the DPS8M cpus, while the execution of
"		    a "cams 4" instruction will only clear cache
"		    for the L68 cpu and is effectively a NOP on the 
"		    DPS8M cpu.
"
"	Usage:	    dcl privileged_mode_ut$clear_cache entry;
"		    call privileged_mode_ut$clear_cache ();
"
"	set_proc_required must be called before calling the clear_cache
"	entry, to assure the the cache on the desired processor is cleared.
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

clear_cache:
	epplb	prds$cache_luf_reg	set ptr to "turn on" constant
	even
	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	lcpr	clear_template,02	turn cache off
	lcpr	lb|0,02		and back on.
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->
	short_return

clear_template:
	oct	3		cache "turn off" constant
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	swap_sdw is called to swap descriptor words for a given
"	segment number.
"
"	The calling sequence is:
"
"		call privileged_mode_ut$swap_sdw (segptr, sdw_ptr)
"
"		Where segptr contains the segment number, sdw is the new
"		descriptor word.  The sdw is an aligned 72 bit quantity.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

swap_sdw:	ldx0	ap|2,*		pick up segment number 
	adlx0	ap|2,*		multiply by 2
	eppbp	ap|4,*		get new descriptor word
	eppbp	bp|0,*
	lda	bp|0
	ldq	bp|1
	staq	dseg$,0		set the SDW

	tsx7	clear_AM_both

	short_return
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"   This entry clears the ptw am on the current processor after 	"
"   mucking with a set of ptws.				"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


camp:
	iftarget	L68
	camp
	ifend
	iftarget  ADP
	decor	ORIONp
	camp1
	ifend
	short_return
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"   This entry clears both AM's after bce mucks with ptws, sdws.	"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
cam_both:
	tsx7	clear_AM_both
	short_return

"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"   These entries are called when we wish to discontinue operation	"
"   of Multics and go to bce.  There can be a return and Multics	"
"   operation resumed.  Since bce must be entered on the bootload 	"
"   processor with all other processors stopped, the actual transfer	"
"   to bce is forced by sending a system trouble connect.		"
"							"
"	Recoded 8 February 1976 by Noel I. Morris		"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


bce_and_return:
bce:
	ldq	prds$processor_tag	get this CPU's tag
	lda	scs$processor_data,ql	get data for this CPU
	cana	processor_data.online,du  during initialization?
	tze	special_go_to_bce	yes

	lda	pds$processid	get process ID
	stac	scs$connect_lock	lock for doing a connect
	nop
	nop
	tnz	*-3		wait until lock set

	stac	scs$trouble_processid " Save if we are the first (its clear)
	lda	scs$processor	processor bits in A
	sta	scs$sys_trouble_pending	set trouble flag

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	cioc	scs$cow_ptrs,ql*		send trouble connect
	dis	*		wait for it to take effect
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

	lda	0,dl		clear the A
	ansa	scs$trouble_processid
	ansa	scs$connect_lock	undo the lock, now

bce_return:
	short_return		Return to caller

" 
	use	linkage
	join	/link/linkage

	even
save_drl:	bss	,2
save_luf: bss	,2
drl_to_do:bss	,2
	
	use	main

	eight
ignore_data:
	bss	,8

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

ignore_scu_rcu:
	scu	0
	rcu	0
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"							"
" special_bce_return - used by bce to return to bos or multics	"
"							"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

special_bce_return:
	ldaq	ap|2,*			arg is pair to put into drl 
	staq	lp|drl_to_do		fault vector
	tra	leave_multics

special_go_to_bce:
	ldaq	toehold$+2*TOE_HOLD_MULTICS_ENTRY	get interrupt pair
	staq	lp|drl_to_do

leave_multics:
	eppbb	fault_vector$
	ldaq	bb|2*FAULT_NO_LUF+fv.fpair	save lockup fault vector
	staq	lp|save_luf
	absa	ignore_data	abs addr in 0-23
	als	6		abs addr in 0-17 Areg
	eaq	0,au		abs addr in 0-17 Qreg
	oraq	ignore_scu_rcu	new lockup fault vector
	staq	bb|2*FAULT_NO_LUF+fv.fpair

	lda	8,du		loop waiting for i/o to die down
	odd
	sba	1,dl
	tnz	*-1

	ldaq	bb|2*FAULT_NO_DRL+fv.fpair	pick up derail from fault vector
	staq	lp|save_drl	save for restore later
	ldaq	lp|drl_to_do	get interrupt pair
	staq	bb|2*FAULT_NO_DRL+fv.fpair	store into derail slot of fault vector

	drl			" go to bce

	ldaq	lp|save_drl	restore derail fault pair
	staq	bb|2*FAULT_NO_DRL+fv.fpair
	ldaq	lp|save_luf	restore lockup fault pair
	staq	bb|2*FAULT_NO_LUF+fv.fpair

	tra	bce_return

	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	rsw and trace_rsw are called in order to execute the rsw privileged instruction.
"		They return in "value" the same bits returned after
"		the rsw instruction is executed trace_rsw does not require rsw_code to be
"		input.
"		Instead it is assumed to be zero.
"
"	Usage:
"
"		% include rsw;
"		dcl rsw_code fixed(35), value bit(36) aligned;
"		call privileged_mode_ut$rsw ( rsw_code, value );
"		call privileged_mode_ut$trace_rsw ( value );
"
"	rsw_code  is 0, 1, 2, 3 or 4, depending on what bits are to be read by
"		rsw. See the processor manual for the definition of these.
"		This procedure does not check that rsw_code is 0, 1, 2, 3 or 4.
"		(Input).
"
"	value	is the bit string put in the a-register by rsw. See the
"		rsw.incl.pl1 file and the
"		processor manual for the meaning of this. (Output).
"
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "



rsw:
	lxl0	ap|2,*		c(x0) = rsw_code.
	rsw	0,0		Get value.
	sta	ap|4,*
	short_return


trace_rsw:
	rsw	0		Get value.
	sta	ap|2,*
	short_return
"
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"
"  read_id_prom
"  	used to read a selected string of  bytes  (characters)  from
"  	the ID PROM of a DPS8 CPU
"
"  Usage:
"  	dcl  privileged_mode_ut$read_id_prom entry (char (*) aligned, fixed bin);
"  	call privileged_mode_ut$read_id_prom (id_string, start_pos);
"
"  where:
"
"  id_string	is an aligned character string, in which the ID PROM info is
"		to  be  stored. The number of bytes to read is obtained from
"		the argument descriptor (length) of id_string.
"
"  start_pos	is the first byte number to be read from the ID PROM
"
"  This subroutine will only work for DPS8  cpus,  indeterminent  results
"  will  be  obtained if this subroutine is executed on a L68 or DPS cpu.
"  The calling routine should guarantee execution on the desired  CPU  by
"  first calling pxss$set_proc_required.
"
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

read_id_prom:
	push
	lxl7	ap|4,*		get starting byte number
	lxl6	ap|6,*		and target string length from desc.
	anx6	=o77,du		allow only 63 characters
	eppbp	ap|2,*		get ptr to target string
	epaq	rip_str1		ptr to  temp string in AQ
	lls	18		string ptr word offset in AL
	eaq	0,6		copy string length
	qls	6		position tally count
	orq	32,du		or in 9 bit char type
	lls	18		tally word in A
	sta	tally_wd		store tally word (starting char pos = 0)
	lda	rsw_template	get rsw instruction template
	sta	rsw_xec		and store in stack
rip_lp1:	stx7	rsw_xec		set byte number in rsw instruction
	xec	rsw_xec		execute the rsw instruction
	ana	=o377,dl		and out M.S bit  in case it is set
	sta	tally_wd,sc	store ID byte in string
	ttn	rip_exit		return on tally runout
	eax7	1,7		increment byte number
	tra	rip_lp1		and get next ID byte

rip_exit:
	mlr	(pr,rl),(pr,rl),fill(040)
	desc9a	rip_str1,x6	copy ID string to user storage
	desc9a	bp|0,x6
	return

rsw_template:
	rsw	0,dl		used to read ID prom
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	rscr and sscr are called in order to execute the rscr and sscr
"		instructions, respectively. "value" is the output or input argument
"		for these instructions as specified in the processor manual,
"		respectively.
"
"	Usage:
"
"		% include scr;
"		dcl scr_input bit(36) aligned, value bit (72) aligned;
"		call privileged_mode_ut$rscr (port_no, scr_input, value );
"		call privileged_mode_ut$sscr (port_no, scr_input, value );
"
"	scr_input  is one of the legal arguments specified as a  y-field in
"		an rscr or sscr instruction. See the processor manual
"		and the scr.incl.pl1 file for an
"		explanation of the legal values of scr_input. This procedure
"		does not verify that a legal value of scr_input was input.
"		(Input).
"
"	value	is the bit string read or stored by rscr or sscr, respectively.
"		See the processor manual and the scr.incl.pl1 file for the
"		definition of this bit string.
"		(Output of rscr. Input of sscr.)
"
"	port_no	Is the processor port number to which the
"		rscr or sscr instruction is to be directed.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

rscr:
	lda	ap|2,*		port number in A
	als	10-3		multiply by 128
	adla	ap|4,*		add in scr_input
	als	3		port*1024 + scr_input*8
	rscr	scas$,al		read controller regs
	staq	ap|6,*		Output value.
	short_return



sscr:
	lda	ap|2,*		port number in A
	als	10-3		multiply by 128
	adla	ap|4,*		insert scr_input
	als	3		port*1024 + scr_input*8
	eax0	0,al		place in X0
	ldaq	ap|6,*		Get input value.
	sscr	scas$,0	set controller regs
	short_return
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	smcm is called to execute the smcm instruction unconditionally.
"
"	Usage:
"		dcl port_no fixed bin (3), mask bit (72) aligned;
"		call privileged_mode_ut$smcm (port_no, mask);
"
"	port_no 	is the processor port number to which the smcm
"		is directed.
"
"	mask	is the mask to be set by an SMCM instruction.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

smcm:
	lxl1	ap|2,*		port number in X1
	ldaq	ap|4,*		mask in AQ
	smcm	scs$port_addressing_word,1*	set the mask

	short_return

"

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	privileged_mode_ut$ldt
"
"         loads the timer register with its argument.
"
"         declare privileged_mode_ut$ldt entry (fixed bin (35));
"         call privileged_mode_ut$ldt (timer);
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

ldt:
	ldt	ap|2,*		load the timer
	short_return

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	ldbr
"
"	This entry loads a new dbr for make_segs_paged,
"	which has just finished setting up ASTE's and
"	SDW's in a new dseg for the paged segments.
"
"	Call is:
"
"	     call privileged_mode_init$ldbr(new_dbr)
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+>
ldbr:
	ldbr	ap|2,*		load the new DBR
	inhibit   off       <-><-><-><-><-><-><-><-><-><-><->
	short_return



" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	smic is called to set an interrupt pattern in the bootload SCU
"
"	Usage:
"		dcl privileged_mode_ut$smic entry (bit (36));
"		call privileged_mode_ut$smic (smic_pattern);
"
"	smic_pattern  is a bit pattern to be used by the SMIC
"		instruction.
"
"	smic_port is called to set an interrupt pattern in any SCU
"
"	Usage:
"		dcl privileged_mode_ut$smic_port entry (bit (36), fixed bin (5));
"		call privileged_mode_ut$smic_port (smic_pattern, port_number);

"	port_number is the port to which to send the smic instruction
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

smic_port:
	lxl7	ap|4,*			pick up port number in X7
	tra	smic_common

smic:
	lxl7	scs$interrupt_controller  	bootload controller port in X7

smic_common:
	lda	ap|2,*		pick up 	SMIC pattern in A
	smic	scs$port_addressing_word,7*  	SMIC

	short_return

" 
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	pmut$check_for_mem_overlap
"
"	This entry is used to determine if a memory addressing overlap
"	exists in an SCU.
"
"	It is called during SCU initialization.
"
"	It returns a nonzero code if a memory overlap error is found.
"
"	call is:
"
"	call pmut$check_for_mem_overlap (low_block, high_block, code)
"
"	low_block, high_block are 1024-word frame numbers, code is returned
"	nonzero if a memory overlap error is found
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
check_for_mem_overlap:
	push
	ldx0	lp|abs_seg_link	get segno of abs_seg
	adlx0	lp|abs_seg_link	multiply by 2 (SDW size)
	ldx1	lp|abs_seg_link1	get segno of abs_seg1
	adlx1	lp|abs_seg_link1	multiply by 2 (SDW size)
	ldaq	dseg$,0		pick up old contents of abs_seg SDW
	staq	save_sdw		save in stack
	ldaq	dseg$,1		pick up old contents of abs_seg1 SDW
	staq	save_sdw1		save in stack
	ldq	ap|2,*		pick up low address input arg
	stq	new_low_data	save for check
	lls	36+12+10		36 for a, 12 for sdw, 10 for 1024 word blocks
	oraq	abs_seg_sdw	make an SDW out of the a-q
	staq	dseg$,0		place in SDW slot for abs_seg
	ldq	ap|4,*		pick up high address input arg
	stq	new_high_data	save for check
	lls	36+12+10		36 for a, 12 for sdw, 10 for 1024 word blocks
	oraq	abs_seg_sdw	make an SDW out of the a-q
	staq	dseg$,1		place in SDW slot for abs_seg1
	tsx7	clear_AM_segs
	sti	save_indicators	save the indicators
	sti	indicators_no_par	save current indicators
	lda	indicators_no_par	we must turn OFF parity indicator
	ana	-1-scu.par,dl	..
	ora	scu.parm,dl	and turn ON parity mask
	sta	indicators_no_par	
	eppap	abs_seg$		ap -> low address to check
	eppbp	abs_seg1$		bp -> high address to check
	ldi	indicators_no_par
	lda	ap|0		get low address contents
	sta	old_low_data	and save for later restore
	lda	bp|0		get high address contents
	sta	old_high_data	and save for possible later restore
	lda	new_low_data
	sta	ap|0		save low address in low address
	lda	new_high_data
	sta	bp|0		save high address in high address

	lda	ap|0		now check contents of low address
	cmpa	new_low_data	against what was originally written
	tnz	overlap_error	if OVERLAP leave non-zero data in A-reg
	lda	0,dl		otherwise zero A-reg for return code

	ldq	old_high_data	replace original high data
	stq	bp|0		when no error detected

overlap_error:
	ldq	old_low_data	replace original low data
	stq	ap|0		even when error is found
	eppap	sp|stack_frame.arg_ptr,*	restore arg pointer
	sta	ap|6,*
	ldaq	save_sdw		restore abs_seg SDW
	staq	dseg$,0
	ldaq	save_sdw1		restore abs_seg1 SDW
	staq	dseg$,1
	tsx7	clear_AM_segs
	ldi	save_indicators
	return


" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	pmut$check_parity_for_use
"
"	This entry is used to determine if a parity error exists in a main memory frame.
"
"	It is called 
"	when hardware_fault catches a store parity error, in which case
"		all configured main memory is checked.
"
"	It returns a code if a parity error is found.
"	It leaves the responsibility of getting the
"	data page somewhere else without a parity error on page control,
"	who will subsequently be called to delete the page anyway.
"
"	call is:
"
"	call pmut$check_parity_for_use (blocknumber, code)
"
"	blocknumber is 1024-word frame number, code returned nonzero if parity
"	error found
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
check_parity_for_use:
	push
	aos	lp|check_parity_calls	meter calls
	ldx0	lp|abs_seg_link	get segno of abs_seg
	adlx0	lp|abs_seg_link	multiply by 2 (SDW size)
	ldaq	dseg$,0		pick up old contents of abs_seg SDW
	staq	save_sdw		save in stack
	ldq	ap|2,*		pick up core address as input argument
	lls	36+12+10		36 for a, 12 for sdw, 10 for 1024 word blocks
	oraq	abs_seg_sdw	make an SDW out of the a-q
	staq	dseg$,0		place in SDW slot for abs_seg
	tsx7	clear_AM_segs

	sti	save_indicators	save the indicators
	sti	indicators_no_par	save current indicators
	lda	indicators_no_par	we must turn OFF parity indicator
	ana	-1-scu.par,dl	..
	ora	scu.parm,dl	and turn ON parity mask
	sta	indicators_no_par	
	eppap	abs_seg$		ap -> page to check
	ldx1	1024*4,du		size of a page in characters

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

	ldi	indicators_no_par
	cmpc	(pr,rl),(pr,rl)	read entire page without modifying
	desc9a	ap|0,x1
	desc9a	ap|0,x1
	nop	0
	nop	0

" 	The cmpc may not have examined all words in the page, since another
"	CPU or an IOM could modify a double-word between the two fetches.
"	If this happens, we punt, and check the page the hard way.

	tnz	slow_pc		lost race -- do it the hard way

	sti	indicators

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

	lda	0,dl		pre-set error code to 0
	ldq	indicators	check for a parity error
	canq	scu.par,dl	..
	tze	checkpar_returns_code  None found
checkpar_report_error:
	lda	1,dl		non-zero error code
	tra	checkpar_returns_code

slow_pc:	aos	lp|check_parity_slow  count these
	eax1	1022		check page a double-word at a time

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

slow_pc_loop:
	ldaq	abs_seg$,1	
	nop	0		let things settle
	nop	0
	sti	indicators
	ldi	indicators_no_par

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

	ldq	indicators	check for a parity error
	canq	scu.par,dl
	tnz	checkpar_report_error
	eax1	-2,1
	tpl	slow_pc_loop
	lda	0,dl		zero error code

checkpar_returns_code:
	eppap	sp|stack_frame.arg_ptr,*	restore arg pointer
	sta	ap|4,*
	ldaq	save_sdw		restore abs_seg SDW
	staq	dseg$,0
	tsx7	clear_AM_segs
	ldi	save_indicators
	return

" 	check_parity_for_add
"	
"	This entrypoint is just as the above, except that
"	is clears the memory first to get rid of parity errors
"	left from uninitialized SCU's.

check_parity_for_add:
	push
	aos	lp|check_parity_calls	meter calls
	ldx0	lp|abs_seg_link	get segno of abs_seg
	adlx0	lp|abs_seg_link	multiply by 2 (SDW size)
	ldaq	dseg$,0		pick up old contents of abs_seg SDW
	staq	save_sdw		save in stack
	ldq	ap|2,*		pick up core address as input argument
	lls	36+12+10		36 for a, 12 for sdw, 10 for 1024 word blocks
	oraq	abs_seg_sdw	make an SDW out of the a-q
	staq	dseg$,0		place in SDW slot for abs_seg
	tsx7	clear_AM_segs

	sti	save_indicators	save the indicators
	sti	indicators_no_par	save current indicators
	lda	indicators_no_par	we must turn OFF parity indicator
	ana	-1-scu.par,dl	..
	ora	scu.parm,dl	and turn ON parity mask
	sta	indicators_no_par	
	eppap	abs_seg$		ap -> page to check
	ldx1	1024*4,du		size of a page in characters

	mlr	(),(pr,rl)	zero entire page
	desc9a	0
	desc9a	ap|0,x1

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

	ldi	indicators_no_par

	cmpc	(pr,rl),(pr,rl)	read entire page without modifying
	desc9a	ap|0,x1
	desc9a	ap|0,x1
	nop	0
	nop	0

	sti	indicators
	
	inhibit	off		<-><-><-><-><-><-><-><-><-><-><-><->

	lda	0,dl		pre-set error code to 0
	ldq	indicators	check for a parity error
	canq	scu.par,dl	..
	tze	checkpar_returns_code  None found
	tra	checkpar_report_error  Borrow returns from _for_use

	even
abs_seg_sdw:
	vfd	o36/sdw.valid
	vfd	1/,o14/37777,3/sdw.read+sdw.write,o18/sdw.unpaged

clear_AM_both:
	iftarget	L68
	camp
	ifend
	iftarget  ADP
	decor	ORIONp
	camp1
	ifend
clear_AM_segs:
	iftarget  L68
	cams
	ifend
	iftarget  ADP
	decor	ORIONp
	cams1
	decor	L68
	ifend
	tra	0,x7

	use	.link
check_parity_calls:
	dec	0
check_parity_slow:
	dec	0
	use	.text.

	join	/link/.link

	include	apte
	include	fault_vector
	include	mode_reg
	include	ptw
	include	sdw
	include	sst
	include	scs
	include	stack_frame
	include	stack_header
	include	toe_hold
	include	unpaged_page_tables
	end
   



		    syserr.alm                      11/11/89  1106.2r w 11/11/89  0804.9       34704



" ***********************************************************
" *                                                         *
" * 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.      *
" *                                                         *
" ***********************************************************

"
" SYSERR - Procedure to call syserr_real after setting up stack frame.
"	Modified August 1975 by Larry Johnson to add binary and error_code entries
"	Modified 3/76 by S. H. Webber for new reconfig
"	Modified 12/80 by J. J. Bongiovanni for multiplexed ring-0 stacks
"	Modified 4/81 by J. J. Bongiovanni to add checks for wired stack, interrupts masked
"	Modified 10/83 by Keith Loepere for paged unpaged segments.
"	Modified 12/21/84 by EJ Sharpe for multiple_binary

	name	syserr

	entry	syserr
	entry	binary
	entry	error_code
	entry	multiple_binary

	bool	die_offset,030000

" 

	include	ptw

" 

	include	sdw

" 

	include	stack_frame

" 

	include	stack_header
"
	include	unpaged_page_tables

"
"	The main syserr entry is called by ring 0 procedures to type a message on the
"	operator's console.  Its main functions is to transfer this call to syserr_real.
"	If all the conditions listed below are true then we will also adjust the current
"	stack so the next frame will be at a high location in the stack.  This is done so
"	the stack history of the procedures which have just returned to the caller of syserr
"	will not be destroyed.  This stack history may be useful in analyzing a dump of
"	the crash.  The conditions which must all be met before the stack is changed are:
"	1.  The syserr code must be (1).  This => a fatal error.
"	2.  The current stack must be the per-process stack.
"	3.  The per-process stack must be paged.
"	4.  The page table lock must NOT be locked.
"	5.  The current stack must not be wired
"	6.  Interrupts must not be masked

syserr:
	ldx7	0,du			set code to be syserr call
	tra	common
binary:
	ldx7	1,du			set code to be syserr$binary call
	tra	common
error_code:
	ldx7	2,du			set code to be syserr$error_code call
	tra	common

multiple_binary:
	ldx7	3,du			set code to be syserr$multiple_binary

common:
	lda	1,dl			check for kill call
	cmpa	ap|2,*			ARG 1 = 1
	tnz	no_reset			Not a kill call so don't reset

	epaq	sp|0			Ptr to stack to AQ
	eax1	0,au			Seg no to X1
	cmpx1	<pds>|[stack_0_ptr]	          Are we on the per-process stack?
	tnz	no_reset

	als	1			Segno * 2
	ldaq	<dseg>|0,au		Get SDW of stack
	arl	sdw.add_shift		abs addr of stack's page table

	cmpa	unpaged_page_tables$0+upt.sst_last_loc	check if unpaged
	tpl	no_reset			out of sst => unpaged
	sba	unpaged_page_tables$0+upt.sst_absloc	offset of stack's PT in SST
	tmi	no_reset

	lda	sst$,al			PTW for page 0 of stack
	cana	ptw.wired,dl		is it wired
	tnz	no_reset			yes
	
	szn	sst$ptl			is page table locked?
	tnz	no_reset			yes

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+><+><+><+>
	lxl1	prds$processor_tag
	lprpab	scs$mask_ptr,1
	xec	scs$read_mask,1		read current mask
	cmpaq	scs$sys_level		are interrupts masked
	tze	no_reset			yes
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><-><-><-><->

	ldaq	sp|stack_frame.next_sp 	pick up foward ptr
	staq	sp|stack_frame.entry_ptr 	save a copy
	ldq	die_offset,du		Next frame way up in stack.
	stq	sp|stack_frame.next_sp+1 	Reset foward ptr
	stq	sb|stack_header.stack_end_ptr+1

no_reset:
	tra	*+1,7		transfer to correct syserr_real entry
	tra	<syserr_real>|[syserr_real]
	tra	<syserr_real>|[binary]
	tra	<syserr_real>|[error_code]
	tra	<syserr_real>|[multiple_binary]

	end




		    syserr_real.pl1                 11/11/89  1106.2rew 11/11/89  0804.9      293589



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) BULL HN Information Systems Inc., 1989   *
        *                                                         *
        * 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(89-08-28,Farley), approve(89-09-18,MCR8132),
     audit(89-10-10,WAAnderson), install(89-10-11,MR12.3-1091):
     Increased the size of the console output buffer (out_buf) from
     132 to 256 to be consistent with oc_trans_output_.
                                                   END HISTORY COMMENTS */


/* format: style4,indattr,ifthenstmt,ifthen,idind35,^indcomtxt */
syserr_real:
     procedure (arg_code);

/*	This procedure completely recoded  June 28, 1973 by  Bill Silver. */
/* 	Modified 750227 by LJS to change max length of syserr messages */
/*	Modified August, 1975 by Larry Johnson to implement error_code and binary entries */
/*	Modified January 1976 by Larry Johnson to fix bugs in "=" message handling */
/*	Modified March 1976 by Steve Webber to use logger HPROC */
/*	Modified May 1976 by Larry Johnson to add "binary_mylock" entry for use by ocdcm_ */
/*	Modified November 1976 by Larry Johnson to stop logging "=" messages */
/*	Modified May 1977 by Noel I. Morris to shrink stack frame and implement panic */
/*	Modified August 1977 by Noel I. Morris to fix bug in *lost "=" messages */
/*	Modified August 1978 by Bernard S. Greenberg to eliminate calling ocdcm with syserr lock locked. */
/*	Modified April 1982 by C. Hornig to add NL to console messages. */
/*	Modified June 1982 by E. N. Kittlitz to not equalize alarm messages. */
/*   	Modified September 1982 by C. Hornig to use automatic buffer for console */
/*        Modified 830601 BIM to check for silly error codes. */
/* 	Modified 830622 for new ocdcm_ interface... -E. A. Ranzenbach */
/*        Modified 83-12-19 BIM for better call to terminate_proc */
/*	Modified 83-??-?? Keith Loepere for calls to bce. */
/*        Modified 1984-11-26, BIM: options (validate) changed to
	pmut$wire_and_mask, actually call the copy primitive if
	we are called unwired. */
/*	Modified 1984-12-20, BIM: avoid recursive copy attempts by checking
	the paged syserr log lock before actually copying. */
/*	Modified 1984-12-21, EJ Sharpe for multiple_binary entrypoint */
/*	Modified 1985-01-21, EJ Sharpe for 2047 char text (was 512),
	also added process_id to wired msg */
/*	Modified 1985-01-25, Keith Loepere, to fix race in log copying. */
/*	Modified 1985-02-15, Keith Loepere, to restructure syserr paged vs
	wired lock startegy; basically to make the paged lock the 
	highest paged lock in the system so that a copy into the paged lock 
	is always possible from any paged process. */
/*	Modified 1985-03-28, EJ Sharpe, avoid copy to paged log when process
	is to be terminated or system is to be crashed. */

/*	The syserr code which we receive as an argument is converted
   to an action code whose value is mod 10 of the original value.
   The meaning of the ten possible action codes is:
   0  =>  write message without alarm, log, and return.
   1  =>  write message with alarm, log, and CRASH system - allow bce to return.
   2  =>  write message with alarm, log, and terminate process.
   3  =>  write message with alarm, log, and return.
   4  =>  log message and return, don't write message unless message not logged.
   5  =>  log message and return, don't write message even if not logged.
   (6 - 9) not used, mapped into code 5.


   /*		PARAMETER DATA		*/

dcl  arg_code			fixed bin;	/* (I) The syserr code. */
dcl  arg_data_code			fixed bin;	/* (I) Format of binary data on $binary entry */
dcl  arg_data_len			fixed bin;	/* (I) Length of binary data on $binary entry */
dcl  arg_data_pieces_array_ptr	ptr;		/* ptr to array of ptrs and lengths of bin data */
dcl  arg_data_ptr			ptr;		/* (I) Pointer to binary data on $binary entry */
dcl  arg_error_code			ptr unal;		/* (I) error_table_$ code on $error_code entry */
dcl  arg_n_data_pieces		fixed bin;	/* number of pieces of bin data */
dcl  arg_panic_mess			char (*);		/* (I) message to panic entry */


/*		AUTOMATIC  DATA		*/

dcl  alarm_flag			bit (1) aligned;	/* ON => write message with alarm.  */
dcl  arg_list_ptr			ptr;		/* arg list to syserr_real */
dcl  1 auto_mbuf			aligned,		/* refer to DATA STRUCTURING below */
       2 header			like mbuf_header,
       2 equal			char (4) unal;
dcl  1 auto_wlog_header		aligned like wlog_header;
dcl  1 auto_wmess_header		aligned like wmess_header;
dcl  binary_call			bit (1);		/* ON => entered through $binary entry */
dcl  code				fixed bin;	/* copy of code passed to syserr */
dcl  cont_flag			bit (1) aligned;	/* Continuation line flag used by oc_trans_output_. */
dcl  copying_permitted		bit (1) aligned;	/* environment permits page faults */
dcl  cs_pos			fixed bin;	/* Position of ioa_ ccntrol string in param list */
dcl  data_code			fixed bin;	/* Data classification code */
dcl  data_len			fixed bin;	/* Length of binary data */
dcl  data_piece_len			fixed bin;	/* Length of piece of binary data */
dcl  data_piece_ptr			ptr;		/* Pointer to piece of binary data */
dcl  data_pieces_array_ptr		pointer;		/* pointer to array of ptrs and lengths of the pieces of the binary data */
dcl  data_ptr			ptr;		/* Pointer to binary data */
dcl  error_table_call		bit (1);		/* ON => entered through $error_code entry */
dcl  error_table_code		fixed bin (35);
dcl  etmsgp			ptr;		/* Pointer to error table message on $error_code call */
dcl  mbuf_ptr			ptr;		/* Pointer to ASCII message buffer. */
dcl  message_len			fixed bin (21);	/* length of syserr message in data */
dcl  n_data_pieces			fixed bin;	/* number of binary data parts */
dcl  nargs			fixed bin;
dcl  1 oc_io			aligned like console_io;
dcl  oc_line_leng			fixed bin;	/* line length of the console...	*/
dcl  oc_printed_leng		fixed bin;	/* how much we will print on console */
dcl  ocdcm_code			fixed bin (35);	/* returned by ocdcm_...		*/
dcl  old_mask			bit (72) aligned;	/* actually entry value of the mask */
dcl  old_wlog_ptr			ptr;		/* to copy of syserr_data$wired_log_area */
dcl  olen				fixed bin (19);	/* Length  of the output string in  WORDS.  */
dcl  optr				ptr;		/* Pointer to beginning of the output buffer. */
dcl  out_buf			char (256) aligned; /* console buffer */
dcl  piece_index			fixed bin;	/* index of binary data piece */
dcl  print_len			fixed bin (21);	/* number of chars to print on console */
dcl  print_ptr			ptr;		/* Pointer to beginning of expanded message for console */
dcl  print_this_line_len		fixed bin (21);	/* Number  of characters processed. */
dcl  rtime			fixed bin (71);	/* Raw time in microseconds. */
dcl  sys_code			fixed bin;	/* Syserr code of this message. */
dcl  tenths_min			fixed bin;	/* Number of tenths of a minute. */
dcl  wire_arg			bit (72) aligned;	/* mask with pmut's nasty note or'ed into it */
dcl  wired			bit (1) aligned;	/* wired and masked */
dcl  wired_wlog_ptr			ptr;		/* to syserr_data$wired_log_area */
dcl  wired_wmess_ptr		ptr;		/* to where we would add message to syserr_data */
dcl  wired_stack_ptr		pointer;		/* restore value for unwire_unmask */
dcl  wmess_len			fixed bin;	/* Size of current wired message entry. */
dcl  write_flag			bit (1) aligned;	/* ON => this message should be written. */


/*		BASED  DATA		*/

dcl  CR_NL			char (5) based (addr (CR_NL_bits));

/* DATA STRUCTURING:
     This program endeavors to avoid copying data many times.  As such,
it overlays various data structures such that the large data areas need be
copied as seldom as possible.  The idea is to build a wlog structure that
is acceptable to syserr_copy$wired_log.  However, the text in this wlog 
structure also wants to be part of a mbuf structure for console purposes.
So, we lay down the text and data as for a wlog structure, but not the
header.  Instead, we allow for enough room for either a wlog/wmess header,
or a mbuf header, but keep these headers in auto storage, and overlay them
in front of the text when necessary. */

dcl  binary_data			(data_len) bit (36) aligned based (data_ptr); /* binary data on $binary entry */
dcl  data_piece			(data_piece_len) bit (36) aligned based (data_piece_ptr); /* Binary data on $multiple_binary entry */

dcl  1 data_pieces_array		(n_data_pieces) aligned based (data_pieces_array_ptr),
						/* an array of pointers pieces of the binary data */
       2 ptr			pointer,		/* pointer to part of the binary data */
       2 len			fixed bin;	/* number of words */

dcl  1 et				aligned based (etmsgp), /* An error table message */
       2 len			fixed bin (8) unal, /* Length of the message */
       2 msg			char (et.len) unal; /* The message */

/* This buffer will hold the ASCII message.  When writing a message the string will
   start at either  mbuf.no_log or mbuf.time  and extend to and include mbuf.text. */

dcl  1 mbuf			aligned based (mbuf_ptr),
       2 header			aligned like mbuf_header,
       2 text			char (2047) unal;	/* Expanded syserr message in ASCII. */

dcl  1 mbuf_header			aligned based,
       2 no_log,					/* Special message written only if there is no room
						   in the wired log buffer for this message entry. */
         3 lost			char (6) unal,	/* "*lost " */
         3 seq_num			pic "9999" unal,
         3 comma			char (2) unal,	/* ", " */
         3 sys_code			pic "9" unal,
         3 pad			char (3) unal,
       2 time,					/* Time message logged.  Converted to:  "hhmm.t"
						   where t = tenths of minutes. */
         3 hh			pic "99" unal,
         3 mmt			pic "99.9" unal,
         3 pad			char (2) unal;

dcl  old_wlog			(syserr_data$wired_log_size) bit (36) aligned based (old_wlog_ptr);
						/* allocated copy of syserr_data$wired_log_area */

dcl  wmess_copy			(wmess_len) bit (36) aligned based; /* for copying wmess into syserr_data */


/*		EXTERNAL ENTRIES CALLED	*/

dcl  arg_count_			entry (fixed bin);
dcl  arg_list_ptr_			entry (ptr);
dcl  formline_			entry (fixed bin, fixed bin, ptr, fixed bin (21), fixed bin, ptr);
dcl  oc_trans_output_		entry (ptr, fixed bin (21), fixed bin (21), ptr, fixed bin (19), fixed bin, bit (1) aligned);
dcl  ocdcm_$console_info		entry (char (4), bit (36), char (8), fixed bin, fixed bin, fixed bin (35));
dcl  ocdcm_$drain_io		entry ();
dcl  ocdcm_$priority_io		entry (ptr);
dcl  pmut$bce_and_return		entry options (variable);
dcl  pmut$read_mask			entry (bit (72) aligned);
dcl  pmut$set_mask			entry (bit (72) aligned);
dcl  pmut$unwire_unmask		entry (bit (72) aligned, pointer);
dcl  pmut$wire_and_mask		entry (bit (72) aligned, pointer);
dcl  pxss$unique_ring_0_wakeup	entry (bit (36) aligned, fixed bin (71), fixed bin (71), fixed bin (35));
dcl  syserr			entry options (variable);
dcl  syserr_copy$lock		entry ();
dcl  syserr_copy$unlock		entry ();
dcl  syserr_copy$wired_log		entry (ptr);
dcl  syserr_real$syserr_real		entry options (variable);
dcl  terminate_proc			entry (fixed bin (35));
dcl  wired_utility_$grow_stack_frame	entry (fixed bin) returns (ptr);


/*		EXTERNAL DATA	 */

dcl  error_table_$			ext;
dcl  pds$process_group_id		char (32) aligned ext;
dcl  pds$processid			bit (36) aligned ext;
dcl  pds$apt_ptr			pointer ext;
dcl  prds$			ext;
dcl  prds$idle_ptr			pointer ext;
dcl  scs$open_level			bit (72) aligned ext;
dcl  sys_info$time_correction_constant	fixed bin (71) ext;
dcl  syserr_data$logger_ec		fixed bin (71) ext;
dcl  syserr_data$logger_proc_id	bit (36) aligned ext;
dcl  syserr_data$wired_log_size	fixed bin ext;


/*		MISCELANEOUS	*/

dcl  cleanup			condition;

dcl  (add, addcharno, addr, addrel, baseno, bin, bit, byte, clock, currentsize, divide, length, max, min, mod, multiply, ptr, rel, rtrim, segno, size, stac, stackbaseptr, stacq, string, substr, unspec, wordno) builtin;


/*		CONSTANTS		*/

dcl  CR_NL_bits			bit (45) static options (constant) init ("015012177177177"b3); /* cr, nl, 3 pads - 
					sufficient to add nl to console string */
dcl  bad_ring1_msg			char (24) static options (constant) init ("syserr: Bad ring 1 call.");
dcl  crash_msg			char (46) static options (constant) init ("Multics not in operation; control process: ^a.");
dcl  lock_msg			char (21) static options (constant) init ("syserr: Mylock error.");
dcl  terminate_msg			char (33) static options (constant) init ("Now terminating user process: ^a.");
%page;

/*	MAIN  SYSERR_REAL  ENTRY  -  CALLED BY  SYSERR */

	cs_pos = 2;				/* formline_ control string is second param */
	call ring0_setup;

syserr_start:
	data_len = 0;

	call arg_list_ptr_ (arg_list_ptr);
	call SETUP_AND_TEXT;
	go to COMMON;


/* Entry point if binary data is included */

binary:
     entry (arg_code, arg_data_ptr, arg_data_code, arg_data_len);

	cs_pos = 5;				/* formline_ control string is 5th param */
	call ring0_setup;

syserr_binary_start:
	data_len = arg_data_len;

	call arg_list_ptr_ (arg_list_ptr);
	call SETUP_AND_TEXT;
	if data_len > 0 then do;			/* If there is binary data */
	     binary_call = "1"b;			/* this is binary call */
	     data_code = arg_data_code;
	     data_ptr -> binary_data = arg_data_ptr -> binary_data; /* Copy to wired stack */
	end;

	go to COMMON;


/* Entry point if binary data is supplied in pieces */

multiple_binary:
     entry (arg_code, arg_data_pieces_array_ptr, arg_n_data_pieces, arg_data_code);

	cs_pos = 5;
	call ring0_setup;

syserr_multiple_binary_start:
	data_pieces_array_ptr = arg_data_pieces_array_ptr;
	n_data_pieces = arg_n_data_pieces;
	data_len = 0;
	do piece_index = 1 to n_data_pieces;
	     data_len = data_len + data_pieces_array (piece_index).len;
	end;

	call arg_list_ptr_ (arg_list_ptr);
	call SETUP_AND_TEXT;

	if data_len > 0 then do;
	     binary_call = "1"b;			/* there's something for us */
	     data_code = arg_data_code;
	     data_piece_ptr = data_ptr;
	     do piece_index = 1 to n_data_pieces;	/* copy it piece by piece */
		data_piece_len = data_pieces_array (piece_index).len;
		data_piece_ptr -> data_piece = data_pieces_array (piece_index).ptr -> data_piece;
		data_piece_ptr = addrel (data_piece_ptr, data_piece_len);
	     end;
	end;
	goto COMMON;


/* Enter here with error code to expand */

error_code:
     entry (arg_code, arg_error_code);

	cs_pos = 3;				/* formline_ control string is 3rd */
	call ring0_setup;

syserr_error_start:
	error_table_call = "1"b;
	data_len = 0;

	call arg_list_ptr_ (arg_list_ptr);
	call SETUP_AND_TEXT;
	go to COMMON;
%page;

/* Ring 1 entry points to syserr. These entries are the same as the corresponding ring 0
   entries, except that a ring 1 caller is not allowed to crash the system or terminate a process. */

ring1:
     entry (arg_code);

	cs_pos = 2;				/* control string is second */
	call arg_count_ (nargs);			/* get argument count */
	call ring1_setup;
	go to syserr_start;				/* normal ring0 entry starts here */


ring1_error_code:
     entry (arg_code, arg_error_code);

	cs_pos = 3;				/* control string is 3rd  */
	call arg_count_ (nargs);			/* get argument count */
	call ring1_setup;
	go to syserr_error_start;			/* ring0 entry starts here */


ring1_binary:
     entry (arg_code, arg_data_ptr, arg_data_code, arg_data_len);

	cs_pos = 5;				/* control string is 5th */
	call arg_count_ (nargs);			/* get argument count */
	call ring1_setup;
	go to syserr_binary_start;


ring1_multiple_binary:
     entry (arg_code, arg_data_pieces_array_ptr, arg_n_data_pieces, arg_data_code);
	cs_pos = 5;
	call arg_count_ (nargs);			/* get argument count */
	call ring1_setup;
	goto syserr_multiple_binary_start;
%page;
COMMON:
	wired = "0"b;
	on cleanup
	     begin;				/* locks will be unlocked by verify_lock */
	     if wired then call pmut$unwire_unmask (wire_arg, wired_stack_ptr);
	end;
	copying_permitted = "0"b;

	sd_ptr = addr (syserr_data$syserr_area);

	call pmut$read_mask (old_mask);
	if old_mask = scs$open_level then		/* allowing interrupts */
	     if pds$apt_ptr ^= prds$idle_ptr then	/* Not an idle process */
		if stackbaseptr () ^= addr (prds$) then /* Not on the PRDS */
		     if ^termp_flags (sys_code)
			& ^crash_flags (sys_code) then/* not if process/system will disappear */
			if sd.log_flag then		/* WARNING, this is a paged database. */
						/* The following tree touches it IFF all the other conditions are satisfied. */
			     if addr (syserr_log_data$) -> syserr_log_data.lock.pid ^= pds$processid then
						/* Not in the middle of copying the log already */
				copying_permitted = "1"b; /* All these pass? then we can copy here. */

	write_flag = write_flags (sys_code);		/* Set flag if message is to be written */
	alarm_flag = alarm_flags (sys_code);		/* set flag if alarm needed */

	rtime = clock ();				/* Get raw time in microseconds. */

	auto_wmess_header.code = code;		/* fill in wmess header that we can unwired */
	auto_wmess_header.time = rtime;
	auto_wmess_header.pad = "0"b;
	auto_wmess_header.process_id = pds$processid;
	auto_wmess_header.data_code = data_code;

	wired_wlog_ptr = addr (syserr_data$wired_log_area);
						/* place for old messages */
	if copying_permitted then do;			/* when we can copy, we get and hold the paged lock.
						   The wired area is emptied into the paged log, and then we add
						   our message to the paged log.  Our message never goes into the
						   wired area. */
	     call syserr_copy$lock ();
	     old_wlog_ptr = wired_utility_$grow_stack_frame (syserr_data$wired_log_size);
	end;

	call pmut$wire_and_mask (wire_arg, wired_stack_ptr);
	wired = "1"b;

/* Before we reference any data in syserr_data we may have to lock it.
   Note, this lock controls all the data in syserr_data including the wired_log_area. */

	if ^sd.ocdcm_init_flag then call panic (mbuf.text);

	call SR_LOCK ();

/* Now fill in the time of message string that goes before each message.
   It is in the form:  "hhmm.t  ". */

	print_ptr = addr (mbuf.time);			/* For now, console message starts with time. */
	print_len = message_len + length (string (mbuf.time)); /* Get total length of string being written. */

	tenths_min = mod (divide (rtime - sys_info$time_correction_constant, 6000000, 52, 0), 14400);
						/* Number of 10ths of minutes so far today */
	auto_mbuf.header.time.hh = divide (tenths_min, 600, 5);
	auto_mbuf.header.time.mmt = tenths_min - divide (tenths_min, 600, 5) * 600;
	auto_mbuf.header.time.pad = "";
%page;
	if ^sd.log_flag then			/* Is logging mechanism ON? */
						/* NO, can't log message. */
	     auto_wmess_header.seq_num = 0;		/* Thus there is no sequence number. */
	else if copying_permitted then do;

/* look for old messages to copy out */

	     if wired_wlog_ptr -> wlog.count > 0 then do;
		old_wlog_ptr -> old_wlog = wired_wlog_ptr -> old_wlog; /* copy out old messages */
		wired_wlog_ptr -> wlog.next = rel (addr (wired_wlog_ptr -> wlog.buffer)); /* reset wired log */
		wired_wlog_ptr -> wlog.count = 0;
	     end;
	     else old_wlog_ptr -> wlog.count = 0;	/* no old messages */

	     auto_wmess_header.seq_num, wired_wlog_ptr -> wlog.seq_num = wired_wlog_ptr -> wlog.seq_num + 1;
	end;
%page;

/* This code is entered to put the current syserr message into the wired log.
   Each time this procedure is called we want to wake up the syserr
   logger HPROC who takes the messages out of the wired log buffer. */

	else do;

/* Get pointer to this message entry.  We have to fill in the length of the
   text before we know where the end of the entry will be.  Assume for now that
   there is room for this message. */

	     wired_wmess_ptr = ptr (wired_wlog_ptr, wired_wlog_ptr -> wlog.next);

RETRY_ADD:					/* here to retry with a shrunk message */

/* Now check to see if there really is room for this message entry in the wired buffer.
   If not, we will have to write out the message with a special prefix:
   "*lost xxxxxx, z "
   where	 xxxxxx  is the sequence number of the message, and
   z       is the syserr code of the message. */

	     if wmess_len > (size (wlog_header) + wired_wlog_ptr -> wlog.bsize)
		- (bin (wired_wlog_ptr -> wlog.next, 18) - wordno (wired_wlog_ptr)) then do;
						/* Is entry too big?  Do this if YES. */
		if binary_call then do;		/* First try throwing away binary data */
		     binary_call = "0"b;		/* by making it no longer a binary call */
		     wmess_len = wmess_len - auto_wmess_header.data_size;
		     auto_wmess_header.data_size = 0;
		     go to RETRY_ADD;
		end;

		auto_wmess_header.seq_num,		/* Get sequence number of this message. */
		     wired_wlog_ptr -> wlog.seq_num = wired_wlog_ptr -> wlog.seq_num + 1; /* claim sequence number now. */

		if wifnl_flags (sys_code) then do;	/* If message should be written if not logged */
		     write_flag = "1"b;		/* causes message to be written */
		     print_ptr = addr (mbuf.no_log);	/* Now writing special note.  */
		     print_len = print_len + length (string (mbuf.no_log));
		     auto_mbuf.header.no_log.lost = "*lost"; /* initialize work area */
		     auto_mbuf.header.no_log.comma = ",";
		     auto_mbuf.header.no_log.pad = "";
		     auto_mbuf.header.no_log.seq_num = mod (auto_wmess_header.seq_num, 10000);
						/* edit sequence number */
		     auto_mbuf.header.no_log.sys_code = sys_code; /* edit code */
		end;
	     end;
	     else do;

/* There is room for this message in the wired log.  Thus we can fill in the entry. */

		auto_wmess_header.seq_num,		/* Get sequence number of this message. */
		     wired_wlog_ptr -> wlog.seq_num = wired_wlog_ptr -> wlog.seq_num + 1; /* now that we know for sure that we are sending it. */

		wired_wlog_ptr -> wlog.next = bit (add (bin (wired_wlog_ptr -> wlog.next, 18), wmess_len, 18), 18); /* Incr address of where next entry goes. */
		wired_wlog_ptr -> wlog.count = wired_wlog_ptr -> wlog.count + 1; /* Add message to log buffer. */

		wmess_ptr -> wmess.header = auto_wmess_header; /* construct wmess_header in front of message */
		wired_wmess_ptr -> wmess_copy = wmess_ptr -> wmess_copy; /* add wmess to syserr_data */
	     end;

	     call WAKEUP_DAEMON;			/* move these messages! */
	end;
%page;
/* If we don't have to write this message then we are all done.  If we must write it then
   we must first convert it for console output.   Note, a maximum of 80 characters can
   be typed on one line.  With the "no_log" and "time" strings at the beginning of the
   line and since ASCII characters may convert into more than one typed character, it is
   possible the output string will be too long.  In this case the line will be
   continued.  Note, the message itself may consist of more than one line. */

	if write_flag then do;			/*  write - code is (4 - 9). */

/* Check here for a non-alarm syserr message being the same as the last message written.
   If this is the case, only an "=" will be printed. */

	     if ^alarm_flag & mbuf.text = sd.prev_text_written then do;
						/* A match */
		print_len = print_len - message_len + 1;
		message_len = 1;			/* set length to 1 character */
		print_ptr = addrel (addr (auto_mbuf), wordno (print_ptr) - wordno (mbuf_ptr)); /* lie - tell ocdcm_ to print only this header */
		if mbuf.text ^= " " then auto_mbuf.equal = "=";
		else auto_mbuf.equal = "";
						/* substitute "=" unless blank message */
	     end;
	     else do;				/* New message */
		if message_len > length (sd.prev_text_written) then /* too long to save */
		     unspec (sd.prev_text_written) = "0"b;
						/* so clear out old message */
		else sd.prev_text_written = substr (mbuf.text, 1, message_len);
						/* save text */
		mbuf_ptr -> mbuf_header = auto_mbuf.header; /* get the real mbuf header in front of the message for printing */
	     end;
	end;
%page;
/* Syserr data has been globally updated.  Now we need to write the actual message, which is done from data in the stack. */

	call SR_UNLOCK;				/* Unlock syserr data */

	if write_flag then do;
	     optr = addr (out_buf);			/* Pointer to output buffer. */
	     cont_flag = "0"b;			/* => 1st line of message.  oc_trans_output_ turns
						   it ON in case of a continuation line.  */

/* Each iteration processes 1 console output line.
   There may be more than one line in the syserr
   message or there may be a continuation line. */


	     call ocdcm_$console_info ("", "0"b, "", 0, oc_line_leng, ocdcm_code);
						/* get console line length...		*/
	     if ocdcm_code ^= 0 then oc_line_leng = 80;	/* default line length...		*/

	     do while (print_len > 0);
		call oc_trans_output_ (print_ptr, print_len, print_this_line_len, optr, olen, oc_line_leng, cont_flag);
		oc_printed_leng = multiply (olen, 4, 17);

		oc_io.read = "0"b;
		oc_io.alert = alarm_flag;
		oc_io.sequence_no = auto_wmess_header.seq_num;
		oc_io.event_chan = 0;

		if print_this_line_len >= print_len then do; /* this is the last line - add CR NL */
		     oc_printed_leng = length (rtrim (substr (out_buf, 1, oc_printed_leng), byte (127))); /* actual last char */
		     substr (out_buf, oc_printed_leng + 1, 5) = CR_NL;
		     olen = divide (oc_printed_leng + 5, 4, 17); /* 2 for cr/nl, 3 for rounding up to word */
		     oc_printed_leng = multiply (olen, 4, 17);
		end;

/* advance for next line */
		print_ptr = addcharno (print_ptr, print_this_line_len);
		print_len = print_len - print_this_line_len;
		alarm_flag = "0"b;			/* Don't want alarm ON more than once. */

		oc_io.leng = olen;
		oc_io.text = substr (out_buf, 1, oc_printed_leng);

		call ocdcm_$priority_io (addr (oc_io)); /* do the I/O...*/
	     end;
%page;

/*	Now check to see if we have to terminate the process or CRASH the system.  */

	     if termp_flags (sys_code) then do;		/* If process to be terminated */
		call syserr_real$syserr_real (LOG, terminate_msg, pds$process_group_id);
		call pmut$set_mask (scs$open_level);	/* Unmask so that recursive call wires */
		call terminate_proc (error_table_code);
	     end;


	     else if crash_flags (sys_code) then do;	/* If system is to crash */

/* TOO BAD we must CRASH.  Before we call bce we must be sure that all of the messages on
   the ocdcm_ syserr write queue have been written.  We will call a special entry
   in  ocdcm_ which completes all pending I/O. */

		call syserr_real$syserr_real (ANNOUNCE, crash_msg, pds$process_group_id);

		call ocdcm_$drain_io ();		/* flush pending I/O...		*/

		call pmut$bce_and_return;
	     end;
	end;
%page;

/* Time to leave */

	call pmut$unwire_unmask (wire_arg, wired_stack_ptr);

	if copying_permitted then do;
	     if old_wlog_ptr -> wlog.count > 0 then call syserr_copy$wired_log (old_wlog_ptr);
	     wlog_ptr -> wlog_header = auto_wlog_header;	/* reconstruct wlog header before text */
	     wlog.count = 1;
	     wmess_ptr -> wmess_header = auto_wmess_header;
	     call syserr_copy$wired_log (wlog_ptr);	/* add in our new message */
	     call syserr_copy$unlock;
	end;
	return;
%page;
/* All this entry does is force the  sd.lock  OFF.  */

syserr_reset:
     entry;

	addr (syserr_data$syserr_area) -> sd.lock = "0"b;

	return;


/* This entry is called if syserr is called before the IOM and operator's
   console software has been initialized.  It is also called when trouble
   is encountered in syserr or ocdcm_. */

panic:
     entry (arg_panic_mess);

	fgbxp = addr (flagbox$);			/* Get pointer to bce flagbox. */
	fgbx.message = arg_panic_mess;		/* Copy the message. */
	fgbx.alert, fgbx.mess = "1"b;			/* Turn on flag bits. */

	do while ("1"b);				/* Back to bce. */
	     call pmut$bce_and_return;
	end;
%page;

/* common processing for ring 1 calls */

ring1_setup:
     proc;

	binary_call = "0"b;				/* defaults */
	data_code = 0;
	error_table_call = "0"b;

	if nargs < cs_pos then do;			/* if not enough */
	     call syserr (4, bad_ring1_msg);
	     go to ring1_return;
	end;
	code = arg_code;				/* copy the code */
	sys_code = mod (code, 10);			/* compute action code */
	code = divide (code, 10, 17, 0);		/* check sort code */
	if code < 0 | code > 24 then code = 24;		/* apply default if out of range */
	code = 10 * code + sys_code;			/* this is new code after errors removed */

     end ring1_setup;


ring1_return:
	return;					/* nonlocal return from ring1_setup */


ring0_setup: proc;

	binary_call = "0"b;				/* defaults */
	data_code = 0;
	error_table_call = "0"b;

	code = arg_code;				/* copy syserr code */
	sys_code = mod (code, 10);			/* compute action code */
	return;
     end ring0_setup;
%page;

/* This internal procedure is called to unlock the wired log.  */

SR_UNLOCK:
     procedure;

	if stacq (sd.lock, "0"b, sd.lock) then ;	/* Unlock unconditionally */

     end SR_UNLOCK;

SR_LOCK:
     procedure;

	if sd.lock = pds$processid then call panic (lock_msg);
	do while (^stac (addr (sd.lock), pds$processid));
	end;
	return;
     end SR_LOCK;

WAKEUP_DAEMON:
     procedure;

	call pxss$unique_ring_0_wakeup (syserr_data$logger_proc_id, syserr_data$logger_ec, 0, (0));
	return;
     end WAKEUP_DAEMON;
%page;
SETUP_AND_TEXT:
     proc;

/* allocate a wlog structure to hold our message;
   generate the text of the message */

dcl  len_for_et			fixed bin;
dcl  max_header_size		fixed bin;
dcl  text_and_data_size		fixed bin;
dcl  work_ptr			ptr;

	auto_wmess_header.text_len, message_len = 2047;	/* maximum */
	auto_wmess_header.data_size = data_len;

	text_and_data_size = currentsize (addr (auto_wmess_header) -> wmess); /* how much a wmess corresponding to this auto header would need */

	max_header_size = max (size (wlog_header) + size (wmess_header), size (mbuf_header));

	work_ptr = wired_utility_$grow_stack_frame (max_header_size + text_and_data_size); /* Allocate message buffer. */

	wlog_ptr = addrel (work_ptr, max_header_size - (size (wlog_header) + size (wmess_header)));
	wmess_ptr = addrel (wlog_ptr, size (wlog_header));
	mbuf_ptr = addrel (work_ptr, max_header_size - size (mbuf_header));

	call formline_ (cs_pos, cs_pos + 1, addr (wmess.text), message_len, 1, arg_list_ptr);
						/* Expand syserr message. */

	if message_len = 0 then do;			/* if asked to write null message, be careful */
	     substr (wmess.text, 1, 4) = "";		/* clear text buffer */
	     message_len = 1;			/* write 1 blank */
	end;

	error_table_code = -9;
	if error_table_call then do;			/* If passed an error table code */
	     etmsgp = arg_error_code;			/* Copy packed pointer. */
	     unspec (error_table_code) = unspec (arg_error_code);
	     if baseno (etmsgp) = "077777"b3 then	/* If segment is -1 ... */
		etmsgp = ptr (addr (error_table_$), rel (etmsgp));
						/* Use error_table_. */
	     if segno (etmsgp) = 0 then error_table_code = -9;
	     else do;
		len_for_et = auto_wmess_header.text_len - message_len;
						/* Amount of room left to insert message */
		len_for_et = min (len_for_et, et.len + 1);
		if len_for_et > 0 then do;
		     substr (wmess.text, message_len + 1, 1) = " ";
		     substr (wmess.text, message_len + 2, len_for_et - 1) = et.msg;
						/* Concatenate message on end */
		     message_len = message_len + len_for_et;
						/* Adjust message length */
		end;
	     end;
	end;

	auto_wmess_header.text_len = message_len;
	wmess_len = currentsize (addr (auto_wmess_header) -> wmess);
	data_ptr = addrel (wmess_ptr, wmess_len - data_len);
	return;
     end SETUP_AND_TEXT;
%page; %include flagbox;
%page; %include oc_data;
%page; %include syserr_actions;
%page; %include syserr_constants;
%page; %include syserr_data;
%page; %include syserr_log_dcls;
%page;
/*	BEGIN MESSAGE DOCUMENTATION

   Message:
   syserr: Mylock error.

   S:	$crash

   T:	$run

   M:	$err

   A:	$recover


   Message:
   Now terminating user process: PERSON.PROJ.

   S:	$info

   T:	$run

   M:	This line is always preceded by an explanation
   of the error which required the terminaation of the user process
   PERSON.PROJ.

   A:	$ignore


   Message:
   Multics not in operation; control process: PERSON.PROJ.

   S:	$crash

   T:	$run

   M:	This message is always preceded
   by an explanation of the error which crashed the system.

   A:	$recover


   Message:
   syserr: Bad ring 1 call.

   S:	$log

   T:	$run

   M:	A bad call to syserr was made from ring 1.
   The system keeps running.

   A:	$ignore


   END MESSAGE DOCUMENTATION */

     end syserr_real;
   



		    wire_stack.alm                  11/11/89  1106.2r w 11/11/89  0803.8       61650



" ***********************************************************
" *                                                         *
" * 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.      *
" *                                                         *
" ***********************************************************
	name	wire_stack


" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
" Calling Sequence:
"	call wire_stack
"
" This procedure is designed to be called only from PL/1 programs
" through the use of the validate option.
"
" wire_stack performs the following steps:
"	1. If the current stack is the PRDS, or if this is too
"	   early in initialization, return.  Too early in
"	   initialization means before the SCS is set up, as this
"	   is when the masking mechanism is operative.
"	2. A stack frame for wire_stack is created which
"	   overlays the caller's stack frame.
"	3. The memory mask is set to sys_level.
"	4. The current and next pages of the stack are wired down.
"	5. A cleanup condition is established.
"	6. A new stack frame is manfactured for the caller.
"	7. The caller is returned to in his new frame.
"
" The steps above are undone either when the caller returns
" or when a non-local goto occurs.
"
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "


" 

	segref	scs,faults_initialized
	segref	scs,read_mask,mask_ptr,sys_level
	segref	prds,processor_tag
	segref	tc_data,system_shutdown
	segref	privileged_mode_ut,wire_and_mask,unwire_unmask
	segref	condition_,condition_

	link	prds_link,<prds>|0


	tempd	ptp		pointer to stack's page table
	tempd	save_mask		previous memory controller mask
	tempd	label(2)		label for cleanup condition
	tempd	arglist(5)	argument list for call to condition_

" 

	include	stack_header

	include	stack_frame

	include	scs
" 

	entry	wire_stack

wire_stack:

" Ignore this call if on the PRDS or if too early in initialization

	epaq	sp|0		segment # of stack in AU
	eax0	0,au		place in X0
	cmpx0	lp|prds_link	are we on the prds?
	tze	.rt		if so, just return
	ldq	prds$processor_tag
	lda	scs$processor_data,ql	get data for this CPU
	cana	processor_data.online+processor_data.offline,du	early initialization?
	tze	.rt			yes, ignore call

" Ignore this call if masked down.

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	lxl1	processor_tag	CPU tag in X1
	lprpab	mask_ptr,1	get pointer for masking
	xec	read_mask,1	read system controller mask
	eraq	sys_level		masked to sys level?
	anaq	=v16/-1,20/,16/-1,20/  ..
	tze	.rt		if so, ignore the call
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->

" Make stack frame for wire_stack.

	eppap	sp|stack_frame.min_length	establish stack frame for wire stack
	sprisp	ap|stack_frame.prev_sp	leave only the bare minimum of old frame
	eppsp	ap|0			caller's old frame will be rethreaded later
	adwpap	push			ap -> new frame for caller
	spriap	sp|stack_frame.next_sp	set pointer to next frame
	eppbb	sb|stack_header.stack_end_ptr,*  save stack end ptr in bb
	spriap	sb|stack_header.stack_end_ptr	set pointer to new end of stack
	sprilp	sp|stack_frame.lp_ptr	save linkage pointer

" Call privileged_mode_ut$wire_and_mask to do the work.

	eppbp	save_mask		bp -> place for saved controller mask
	spribp	arglist+2		..
	eppbp	ptp		bp -> place for page table pointer
	spribp	arglist+4		..
	ldaq	=v18/4,18/4	set arglist header
	staq	arglist		..

	call	wire_and_mask(arglist) wire and mask

" Set up argument list and call condition_.

	szn	faults_initialized	have faults been initialized yet?
	tze	create_frame	if not, skip call to condition_

	szn	system_shutdown	are we shutting down?
	tnz	create_frame	if so, don't establish condition

	link	cleanup_link,<*text>|[cleanup_handler]
	eppap	lp|cleanup_link,*	make label for cleanup handler
	spriap	label		..
	sprisp	label+2		..

	eppap	lp|condition_name	ap -> character string
	spriap	arglist+2		set up argument list
	eppap	label		ap -> label
	spriap	arglist+4		..
	eppap	lp|condition_name_desc set up descriptor list
	spriap	arglist+6		..
	eppap	lp|label_desc	..
	spriap	arglist+8		..
	ldaq	=v18/4,18/4,18/4	set argument list header
	staq	arglist		..

	sprilp	sp|stack_frame.lp_ptr  be careful to save linkage pair

	call	condition_(arglist)  establish the condition

	epplp	sp|stack_frame.lp_ptr,*	restore the linkage pair now

" Create new stack frame for caller.

create_frame:
	eppbp	sb|stack_header.stack_end_ptr,*  bp -> caller's new frame
	eppap	sp|stack_frame.prev_sp,*	ap -> caller's old frame
	mlr	(pr),(pr)			copy the stack frame header
	desc9a	ap|0,stack_frame.min_length*4	
	desc9a	bp|0,stack_frame.min_length*4	

	eax1	bb|0			X1 contains offset of original end ptr
	sblx1	sp|stack_frame.prev_sp+1	compute length of caller's frame

	sprisp	ap|stack_frame.next_sp	set next sp in old frame
	sprisp	bp|stack_frame.prev_sp	set last sp in new frame
	eppap	bp|0,1			compute next sp for new frame
	spriap	bp|stack_frame.next_sp	and set it
	spriap	sb|stack_header.stack_end_ptr	save new stack end ptr

" Fill in wire_stack's frame with vital info.

	link	return_link,<*text>|[return]
	eppap	lp|return_link,*	ap -> return entry
	spriap	sp|stack_frame.return_ptr	set return control double info
	sprilp	sp|stack_frame.lp_ptr	save pointer so return op will work

" Switch to new frame and return to caller.

	eppsp	bp|0		sp -> new frame
	sprisp	sp|12		doctor the stored prs

.rt:
	eppap	sp|stack_frame.operator_ptr,*	restore pr to operators
	rtcd	sp|stack_frame.return_ptr	return to caller


" 

	entry	return

return:				"normal return from caller
	eppbp	sp|0		bp -> stack frame
	tsx7	undo		unwire and unmask

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	eppsp	sp|stack_frame.prev_sp,*	sp -> caller's old frame
	return			" return to caller's caller
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->


	entry	cleanup_handler

cleanup_handler:			"invoked by non-local goto
push:	push

	ldx0	ap|0		2 * number of args in X0
	eppbp	ap|2,0*		grab display pointer
	tsx7	undo		clean things up

	return			return to the unwinder


" Subroutine to perform unwiring and unmasking.

undo:
	eppap	bp|save_mask	ap -> save mask
	spriap	bp|arglist+2	..
	eppap	bp|ptp		ap -> page table pointer
	spriap	bp|arglist+4	..
	ldaq	=v18/4,18/4	set arglist header
	staq	bp|arglist	..

	call	unwire_unmask(bp|arglist) unwire and unmask

	tra	0,7		return to caller


" 

	even

null:
	its	-1,1		null pointer


	use	internal_static
	join	/link/internal_static

condition_name:
	aci	"cleanup"

condition_name_desc:
	vfd	o18/10121,18/7

label_desc:
	vfd	o18/172


	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
