1 /****^  ***********************************************************
  2         *                                                         *
  3         * Copyright, (C) Honeywell Bull Inc., 1987                *
  4         *                                                         *
  5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  6         *                                                         *
  7         * Copyright (c) 1972 by Massachusetts Institute of        *
  8         * Technology and Honeywell Information Systems, Inc.      *
  9         *                                                         *
 10         *********************************************************** */
 11 
 12 
 13 /****^  HISTORY COMMENTS:
 14   1) change(85-10-30,Swenson), approve(88-07-04,MCR7930),
 15      audit(88-07-11,Parisek), install(88-07-15,MR12.2-1057):
 16      Modified to really fix maxlength increases.
 17                                                    END HISTORY COMMENTS */
 18 
 19 
 20 boundfault: proc (a_mcptr);
 21 
 22 /* Last modified BIM 84-02-06 to handle removal of setfaults for maxlength increases. */
 23 /* last modified by M. Grady on 08/17/79 to fix EIS decimal boundfault case  */
 24 /* last modified by R. Bratt on 09/17/76 for per-process boundfault metering */
 25 /* last modified by A. Bensoussan on 04/25/75 for the new storage system. */
 26 /* last modified by Greenberg on 10-14-74 for SST name table */
 27 /* last modified by Kobziar on 11-15-73 to respect only max_length */
 28 dcl  a_mcptr ptr;
 29 
 30 dcl (tsdwp, old_astep, new_astep, pastep, temptr, kstp, par_astep) ptr,
 31     (pw1, pw2, pageno, segno, csl, pts, old_pts, ptsi) fixed bin,
 32      offset fixed bin (18),
 33      code fixed bin (35),
 34     (time1, time2) fixed bin (71),
 35     (last, relp) bit (18) aligned,
 36     (lsw, par_ehs_status) bit (1) aligned,
 37      tsdw fixed bin (71),
 38      read_lock bit (36) aligned init ("0"b);
 39 
 40 dcl (error_table_$boundviol, error_table_$illegal_deactivation, error_table_$synch_seg_limit,
 41      error_table_$mylock, error_table_$root) ext fixed bin (35),
 42      kst_seg$ ext fixed bin,
 43      pds$bounds_faults fixed bin (35) ext,
 44      dseg$ (0 : 512) bit (72) aligned ext;
 45 
 46 dcl  page$enter_data ext entry (fixed bin, fixed bin),
 47      pc$move_page_table ext entry (ptr, ptr),
 48      syserr entry options (variable),
 49      usage_values ext entry (fixed bin, fixed bin (71)),
 50      sum$getbranch_root_my ext entry (ptr, bit (36) aligned, ptr, fixed bin (35)),
 51      lock$dir_unlock ext entry (ptr),
 52      lock$lock_ast entry,
 53      lock$unlock_ast entry,
 54      get_ptrs_$given_segno ext entry (fixed bin) returns (ptr),
 55      get_aste ext entry (fixed bin) returns (ptr),
 56      get_aste$synchronized entry (fixed bin) returns (ptr),
 57      put_aste ext entry (ptr),
 58      search_ast$hash_in ext entry (ptr),
 59      search_ast$hash_out ext entry (ptr),
 60      setfaults ext entry (ptr, bit (1) aligned);
 61 
 62 declare pmut$swap_sdw entry (pointer, pointer);
 63 declare sdw_util_$set_size entry (pointer, fixed binary (19));
 64 declare sdw_util_$get_address entry (pointer) returns (fixed bin (26));
 65 dcl  sst_seg$ external static;
 66 dcl  sst$pts (0 : 3) fixed bin external static;
 67 dcl  sst$cpu_bf_time fixed bin (71) external static;
 68 dcl  sst$total_bf_pf fixed bin (35) external static;
 69 dcl  sst$total_bf fixed bin (35) external static;
 70 dcl  sstp pointer;
 71 
 72 dcl (addr, baseptr, bin, divide, max, min, null, ptr, rel) builtin;
 73 
 74 
 75 % include mc;
 76 % include trace_types;
 77 % include dir_header;
 78 % include dir_entry;
 79 % include dir_name;
 80 % include aste;
 81 % include sstnt;
 82 
 83 ^L
 84           call usage_values (pw1, time1);                   /* meter bound fault time */
 85           code = 0;
 86           sstp = addr (sst_seg$);                           /* get pointers */
 87           kstp = addr (kst_seg$);
 88           tsdwp = addr (tsdw);
 89 
 90           scup = addr (a_mcptr -> mc.scu (0));
 91           offset = bin (scup -> scu.ca, 18);                /* get the word offset causing the OOB */
 92           pageno = divide (offset, 1024, 17, 0);            /* get the page number in which the word is */
 93           if scup -> scu.apu.ptw2 then pageno = pageno + 1; /* if decimal unit prepage, up page number */
 94           segno = bin (bin (scup -> scu.tsr, 15), 17);      /* get the segment number of the faulting segment */
 95           call page$enter_data (segno, boundfault_start);   /* place entry in the trace list */
 96 
 97           lsw = "1"b;                                       /* set lock switch on */
 98                                                             /* return with entry pointer and dir locked */
 99           call sum$getbranch_root_my (baseptr (segno), read_lock, ep, code);
100           if code ^= 0
101           then if code = error_table_$mylock                /* dir already locked */
102                then lsw = "0"b;                             /* turn off lock switch */
103                else if code = error_table_$root             /* this is the root */
104                then call syserr (2, "boundfault: on the root");
105                else go to update;                           /* for any other error */
106 
107           code = 0;                                         /* May have had a mylock */
108           dp = ptr (ep, 0);                                 /* pointer to directory */
109           if sdw_util_$get_address (addr (dseg$ (segno))) = 0 then go to un; /* if segment not connected, return */
110 
111           temp_entry_name = (addr (ep -> entry.primary_name) -> names.name);
112                                                             /* Copy name into stack, as we cannot
113                                                                touch branch with AST locked */
114           call lock$lock_ast;                               /* lock the AST */
115 
116           old_astep = get_ptrs_$given_segno (segno);        /* get a pointer to the AST entry */
117           if old_astep = null then goto unlock_set;         /* If deactivated since boundfault, return and retake */
118 
119           if pageno >= bin (old_astep -> aste.msl, 9)       /* check max length of segment */
120           then do;
121                code = error_table_$boundviol;               /* return OOB error code */
122                go to unlock_set;                            /* unlock ASTE and DIR and return code */
123           end;
124 
125           if old_astep -> aste.ehs then do;                 /* check for the entry hold switch being ON */
126                code = error_table_$illegal_deactivation;    /* return illegal deactivation */
127                goto unlock_set;
128           end;
129 
130           ptsi = bin (old_astep -> aste.ptsi, 2);           /* get the page table index for the old aste */
131           old_pts = sst$pts (ptsi);               /* get the page table size of the old AST */
132      /**** Before we attempt to find a new, adequately sized page table, ensure
133            that the current page table size is not adequate.  If it is, then all
134            we need to do is update the SDW bounds field.  This discrepancy may
135            occur because, for efficiency reasons, we do not fault the SDW when
136            the maximum length of a segment is increased.  We just wait until
137            the next OOB occurs (this one).  Note that we've already ascertained
138            that the page being referenced is within the ASTE max length. */
139 
140               if pageno < old_pts then                          /* fits within current page table */
141                     begin;
142      declare  temp_sdw bit (72) aligned;
143 
144                temp_sdw = dseg$ (segno);
145 
146                call sdw_util_$set_size ( addr (temp_sdw), min (old_pts, bin (old_astep -> aste.msl, 9)) * 1024); /* fix the sdw */
147                call pmut$swap_sdw (baseptr (segno), addr (temp_sdw));
148 
149                call lock$unlock_ast;
150                code = 0;                                    /* make fim restart */
151                go to un;
152           end;
153 
154           /* ? */ if ptsi >= 3 then do;                     /* already at largest allowed page table size */
155                code = error_table_$boundviol;               /* return illegal bounds violation code */
156 
157 unlock_set:    call lock$unlock_ast;                        /* Unlock the AST */
158                go to un;                                    /* unlock the directory and update meters */
159           end;
160 
161           call setfaults (old_astep, "0"b);                 /* set faults for old AST entry */
162 
163           csl = bin (old_astep -> aste.csl, 9);             /* get the current length of the segment (in pages) */
164           pts = max (pageno+1, csl);                        /* get new page table size */
165 
166           if pts <= old_pts then do;                        /* Used to happen for prepage decimal ops */
167                call lock$unlock_ast;
168                code = error_table_$boundviol;
169                go to un;
170           end;
171 
172 /* Entry hold the father to avoid deactivating him during get_aste */
173 
174           par_astep = ptr (sstp, old_astep -> aste.par_astep);
175           par_ehs_status = par_astep -> aste.ehs;
176           par_astep -> aste.ehs = "1"b;
177 
178 
179           if ^old_astep -> aste.synchronized
180           then new_astep = get_aste (pts);                  /* get a new AST entry */
181           else do;
182                new_astep = get_aste$synchronized (pts);
183                if new_astep = null () then do;
184                     call lock$unlock_ast;
185                     code = error_table_$synch_seg_limit;
186                     goto un;
187                end;
188           end;
189 
190 
191 /* Copy the synchronized switch. This will ensure that page control does the
192    right thing during the page table move, preventing writes before they
193    should be done. */
194 
195           new_astep -> aste.synchronized = old_astep -> aste.synchronized;
196 
197 /* Restore father's ehs status */
198 
199           if new_astep = par_astep then call syserr (1, "boundfault: activating into father ^p", new_astep);
200           par_astep -> aste.ehs = par_ehs_status;
201 
202 /* Now copy the page table from the old entry into the new */
203 
204           call pc$move_page_table (old_astep, new_astep);   /* clean up the page table move */
205           nm_astep = new_astep;
206 
207 
208 /* Now replace the old aste by the new one in the inferior list */
209 
210           pastep = ptr (sstp, old_astep -> aste.par_astep); /* get a pointer to the parent to update the inferior list */
211 
212           last = "0"b;
213           relp = pastep -> aste.infp;                       /* get a pointer to the inferiror list */
214           do while (relp ^= rel (old_astep));               /* loop searching for the current entry */
215                last = relp;                                 /* chain to next, save old */
216                relp = ptr (sstp, relp) -> aste.infl;        /* get next entry in list */
217           end;
218           if last = "0"b then pastep -> aste.infp = rel (new_astep);
219           else ptr (sstp, last) -> aste.infl = rel (new_astep);
220 
221 
222 
223 /* Now update the parent pointers of all inferior entries ( if it's a directory) */
224 
225           relp = old_astep -> aste.infp;
226           do while (relp);                                  /* loop until the end of the list */
227                temptr = ptr (sstp, relp);
228                temptr -> aste.par_astep = rel (new_astep);  /* put in new parent pointer */
229                relp = temptr -> aste.infl;                  /* get the next entry */
230           end;
231 
232 
233 
234           call search_ast$hash_out (old_astep);
235           call search_ast$hash_in (new_astep);
236 
237           call put_aste (old_astep);                        /* Return old ASTE in the free pool */
238 
239 %include make_sstnt_entry;
240 
241           call lock$unlock_ast;
242 un:       if lsw then call lock$dir_unlock (dp);            /* unlock the directory */
243 
244 update:
245           a_mcptr -> mc.errcode = code;
246           call usage_values (pw2, time2);                   /* finish metering */
247           sst$cpu_bf_time = sst$cpu_bf_time + time2 - time1;
248           sst$total_bf_pf = sst$total_bf_pf + pw2 - pw1;
249           sst$total_bf = sst$total_bf + 1;
250           pds$bounds_faults = pds$bounds_faults + 1;
251           call page$enter_data (segno, boundfault_end);
252           return;
253 
254 ill_op_code: entry (a_mcptr);
255 
256 
257           a_mcptr -> mc.errcode = 1;
258           return;
259 
260 /* BEGIN MESSAGE DOCUMENTATION
261 
262    Message:
263    boundfault: on the root
264 
265    S:     $term
266 
267    T:     $run
268 
269    M:     A boundfault on the root directory has been encountered.
270    $err
271 
272    A:     $inform
273 
274 
275    Message:
276    boundfault: activating into father XXX|YYY
277 
278    S:     $crash
279 
280    T:     $run
281 
282    M:     While activating a segment,
283    the parent directory for the segment became deactivated.
284    $err
285 
286    A:     $recover
287 
288 
289    END MESSAGE DOCUMENTATION */
290 
291      end boundfault;