" *********************************************************** " * * " * 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 address ana c_abs_addr_mask,1 make absaddr mod 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 " ----------------------------------------------------------- " " " 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