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 wire_proc: proc (wireptr, code);
 13 
 14 /* This procedure is used to temporarily wire down a hardcore procedure and its linkage
 15    section.  It is assumed that ALL such wiring/unwiring is done by calls to this
 16    procedure.   A data base in the SST header is used to prevent conflicts between different
 17    processes wiring/unwiring tha same segment, and between calls for procedures contained
 18    in the same bound segment.  Linkage segments may be in a combined linkage
 19    segment.  It is assumed that no procedure or linkage has segment number of zero.
 20 
 21    Coded September 1970 by Roger R. Schell
 22    09/10/72, RB Snyder for follow-on
 23    09/18/74, SH Webber to repair locking problems.
 24    08/03/76, N. I. Morris to fix bug referencing linkage header
 25    04/06/81, W. Olin Sibert, for ADP conversion, stacq builtin
 26    10/12/83, Keith Loepere, for paged unpaged segments.
 27    */
 28 
 29           dcl     wireptr                ptr parameter;     /* pointer to the procedure to be wired */
 30           dcl     code                   fixed bin (35) parameter; /* an error code that is returned to caller */
 31 
 32           dcl     linkno                 fixed bin (18);    /* segment number of linkage */
 33           dcl     linkoff                fixed bin (18);    /* offset of our linkage */
 34           dcl     segno                  fixed bin (18);    /* segment number of procedure */
 35           dcl     tseg                   fixed bin (18);    /* segment number temporary */
 36 
 37           dcl     sdwp                   pointer;           /* Must declare here, 'cause include file can't */
 38           dcl     callptr                pointer;           /* pointer into calling procedure */
 39           dcl     freep                  pointer;           /* pointer to a free entry */
 40           dcl     ip                     pointer;           /* pointer to entry of current index */
 41           dcl     linkptr                pointer;           /* pointer to start of linkage */
 42 
 43           dcl     fp                     fixed bin;         /* first page being wired */
 44           dcl     freei                  fixed bin;         /* index of a free entry */
 45           dcl     i                      fixed bin;         /* loop index */
 46           dcl     lp                     fixed bin;         /* last page being wired */
 47           dcl     np                     fixed bin;         /* number of pages being wired */
 48           dcl     size                   fixed bin;         /* size of array of entries */
 49           dcl     temp_fp                fixed bin;         /* temporary */
 50           dcl     temp_lp                fixed bin;         /* temporary */
 51           dcl     increment              fixed bin;         /* incrementing value for count of wiring */
 52 
 53           dcl     wire_call              bit (1) aligned;   /* flag on if this was a call to wire */
 54           dcl     repeated_call          bit (1) aligned;   /* on if are other outstanding calls */
 55           dcl     locked                 bit (1) aligned;   /* flag used during locking process */
 56 
 57           dcl     pds$process_id         bit (36) aligned external static; /* id for locking */
 58           dcl     dseg$                  (0:1023) fixed bin (71) aligned external static;
 59           dcl     unpaged_page_tables$   external;
 60 
 61           dcl     sys_info$system_type   fixed bin external static;
 62           dcl     sst$wire_proc_data     bit (36) aligned external static;
 63           dcl     sst$temp_w_event       bit (36) aligned external static;
 64 
 65           dcl     1 lot$                 aligned like lot external static;
 66 
 67           dcl     error_table_$nolinkag  fixed bin (35) external static; /* error code for no entry in lot */
 68 
 69           dcl     pxss$wait              entry;
 70           dcl     pxss$addevent          entry (bit (36) aligned);
 71           dcl     pxss$delevent          entry (bit (36) aligned);
 72           dcl     pxss$notify            entry (bit (36) aligned);
 73           dcl     get_ptrs_$given_segno  entry (fixed bin (18)) returns (ptr); /* gets astep for a segment number */
 74           dcl     pc_wired$wire_wait     entry (ptr, fixed bin, fixed bin); /* to read into core and wire pages */
 75           dcl     pc_wired$unwire        entry (ptr, fixed bin, fixed bin); /* unwire pages */
 76           dcl     syserr                 entry options (variable); /* prints error message and crashes system */
 77           dcl     wired_utility_$caller  entry () returns (ptr); /* procedure to get pointer to our caller */
 78 
 79           dcl     (addr, baseptr, bin, divide, hbound, max, null, ptr, stac, stacq) builtin;
 80 
 81 /* ^L */
 82 
 83           wire_call = "1"b;                                 /* primary entry is a call to wire */
 84           increment = 1;                                    /* add to count for wire call */
 85           goto join_not_me;
 86 
 87 
 88 wire_proc$unwire_proc: entry (wireptr, code);               /* entry to unwire specified procedure */
 89 
 90           wire_call = "0"b;                                 /* Unwiring. */
 91           increment = -1;                                   /* Decrement counts */
 92 
 93 join_not_me:
 94           code = 0;                                         /* initialize error code to no error */
 95           callptr = wireptr;                                /* copy argument */
 96           go to join;                                       /* join common code */
 97 
 98 
 99 wire_proc$wire_me: entry ();                                /* entry to wire the caller */
100 
101           wire_call = "1"b;                                 /* primary entry is a call to wire */
102           increment = 1;                                    /* when wiring we add 1 to counts */
103           goto join_me;
104 
105 
106 wire_proc$unwire_me: entry ();                              /* entry to unwire the caller */
107 
108           wire_call = "0"b;                                 /* Unwiring. */
109           increment = -1;                                   /* Decrement counts */
110 
111 join_me:  callptr = wired_utility_$caller ();               /* get pointer to our caller */
112                                                             /* and fall through to common code */
113 
114 join:     wpdp = addr (sst$wire_proc_data);                 /* get pointer to data for wire_proc */
115           upt_ptr = addr (unpaged_page_tables$);
116 
117           segno = bin (baseno (callptr), 18);               /* get caller's segment number */
118 
119           locked = stac (addr (wpd.temp_w_lock), pds$process_id); /* try to lock */
120           do while (^locked);
121                call pxss$addevent (sst$temp_w_event);       /* tell TC event to wait on */
122                locked = stac (addr (wpd.temp_w_lock), pds$process_id); /* try to lock again */
123                if ^locked then call pxss$wait;              /* still locked, wait for it */
124                else call pxss$delevent (sst$temp_w_event);  /* locked, clean un unnecessary addevent */
125           end;
126           size = wpd.temp_w_max;                            /* find how far we must search for a match */
127           repeated_call = "0"b;                             /* initialize */
128           freei = hbound (wpd.temp_w, 1) + 1;               /* initialize to null value -- max of 7 entries */
129           twep = null;                                      /* initialize */
130           do i = size + 1 to 1 by -1;                       /* search for the entry we will use */
131                ip = addr (wpd.temp_w (i));                  /* get pointer to current entry */
132                tseg = bin (ip -> twe.segno, 18);            /* find who owns this entry */
133                if tseg = segno                              /* is it us? */
134                then do;
135                          twep = ip;                         /* remember that this is our entry */
136                          if wire_call                       /* check if wire/unwire call */
137                          then repeated_call = "1"b;         /* this is repeated call to wire */
138                          else if bin (twe.count, 18) ^= 1   /* for unwire, check number of calls outstanding */
139                          then repeated_call = "1"b;         /* there are other outstanding calls */
140                     end;
141                if tseg = 0                                  /* check for free entry */
142                then do;                                     /* rememper the free entry */
143                          freep = ip;                        /* remember the free index */
144                          freei = i;
145                     end;
146           end;
147 
148           linkno = binary (baseno (lot$.lp (segno)), 18);   /* get linkage segment number */
149           if linkno = 0                                     /* check for segment that is not valid */
150           then code = error_table_$nolinkag;                /* return error code */
151           else do;                                          /* there is a linkage segment */
152                     if ^repeated_call                       /* check if wired state is already set up */
153                     then do;
154                               if twep = null                /* check if we already have an entry */
155                               then do;                      /* this is the first request to wire procedure */
156                                         linkoff = binary (rel (lot$.lp (segno)), 18); /* get linkage starting offset */
157                                         linkptr = ptr (baseptr (linkno), linkoff); /* make pointer to linkage header */
158                                         if freei > hbound (wpd.temp_w, 1) /* make certain end of array not passed */
159                                         then call syserr (1, "wire_proc: too many temp wired segments."); /* crash */
160                                         else wpd.temp_w_max = max (size, freei); /* update count of wired segs */
161                                         twep = freep;       /* use a free entry */
162 
163                                         twe.seg_w = check_unpaged (addr (dseg$ (segno))); /* unpaged is always wired */
164                                         twe.link_w = check_unpaged (addr (dseg$ (linkno))); /* remember linkage wired */
165 
166                                         twe.segno = bit (segno, 18); /* fill in our segment number */
167                                         twe.linkno = bit (linkno, 18); /* and for our linkage */
168                                         twe.flp = bit (divide (linkoff, 1024, 8, 0), 8); /* compute the first link page */
169                                                             /* compute last page from link length */
170                                         temp_lp = linkoff - 1 + bin (linkptr -> header.block_length, 18);
171                                         twe.llp = bit (divide (temp_lp, 1024, 8, 0), 8);
172                                    end;
173 
174                               if ^twe.link_w                /* check if linkage was initially wired */
175                               then do;                      /* linkage is not initially wired */
176                                         fp, temp_fp = bin (bin (twe.flp, 8), 17); /* get first page number in linkage */
177                                         lp, temp_lp = bin (bin (twe.llp, 8), 17); /* and last page */
178                                         do i = 1 to size;   /* check for overlap of linkage pages */
179                                              ip = addr (wpd.temp_w (i)); /* get pointer to entry */
180                                              if ip ^= twep  /* skip our own entry */
181                                              then if linkno = bin (ip -> twe.linkno, 18) /* if same linkage segment */
182                                                   then if fp = bin (ip -> twe.llp, 8) /* check for conflict with our first page */
183                                                        then fp = temp_fp + 1; /* this page is taken care of by someone else */
184                                                        else if lp = bin (ip -> twe.flp, 8) /* check for conflict with our last page */
185                                                        then lp = temp_lp - 1; /* taken care of , so we skip last page */
186                                         end;
187 
188                                         if fp <= lp         /* check if all linkage pages already wired */
189                                         then do;
190                                                   astep = get_ptrs_$given_segno (linkno); /* get AST pointer for linkage segment */
191                                                   np = lp - fp + 1; /* compute number of pages */
192                                                   if wire_call /* check if wire or unwire */
193                                                   then call pc_wired$wire_wait (astep, fp, np); /* wire down linkage pages */
194                                                   else call pc_wired$unwire (astep, fp, np); /* unwire linkage pages */
195                                              end;
196                                    end;
197 
198                               if ^twe.seg_w                 /* check if procedure was initially wired */
199                               then do;
200                                         astep = get_ptrs_$given_segno (segno); /* get AST pointer for procedure segment */
201                                         if wire_call        /* check if wire or unwire */
202                                         then call pc_wired$wire_wait (astep, 0, -1); /* wire all pages of procedure */
203                                         else call pc_wired$unwire (astep, 0, -1); /* unwire all pages of procedure */
204                                    end;
205 
206                               if ^wire_call                 /* check if we just unwired */
207                               then do;                      /* if unwired, then release our entry */
208                                         twe.segno = (18)"0"b; /* clear procedure segment number */
209                                         twe.linkno = (18)"0"b; /* and linkage segment number */
210                                         if twep = addr (wpd.temp_w (size)) /* check if we have the last entry */
211                                         then wpd.temp_w_max = size - 1; /* reduce count of active entry max */
212                                    end;
213                          end;
214 
215 /* bump counter of outstanding calls */
216                     twe.count = bit (bin (bin (twe.count, 18) + increment, 18), 18);
217                end;
218           if stacq (wpd.temp_w_lock, "0"b, pds$process_id) then call pxss$notify (sst$temp_w_event);
219           else call syserr (1, "wire_proc: lock not locked");
220           return;
221 %page;
222 check_unpaged: proc (sdw_ptr) returns (bit (1) aligned);
223 
224 /* See if the sdw pointed to is unpaged (not page control paged) */
225 
226           dcl     sdw_ptr                pointer;
227 
228           if sys_info$system_type = ADP_SYSTEM then         /* Examine the appropriate SDW */
229                return ((bin (sdw_ptr -> adp_sdw.add, 26) < upt.sst_absloc)
230                     | (upt.sst_last_loc < bin (sdw_ptr -> adp_sdw.add, 26)));
231           else
232                return ((bin (sdw_ptr -> l68_sdw.add, 24) < upt.sst_absloc)
233                     | (upt.sst_last_loc < bin (sdw_ptr -> l68_sdw.add, 24)));
234      end;
235 %page; %include wire_proc_data;
236 %page; %include linkdcl;
237 %page; %include lot;
238 %page; %include aste;
239 %page; %include system_types;
240 %page; %include "sdw.l68";
241 %page; %include "sdw.adp";
242 %page; %include unpaged_page_tables;
243 /* ^L */
244 
245 /* BEGIN MESSAGE DOCUMENTATION
246 
247    Message:
248    wire_proc: too many temp wired segments.
249 
250    S: $crash
251 
252    T: $run
253 
254    M: A request has been made to the supervisor to temp-wire an
255    eighth hardcore segment. Only seven are allowed. Temp-wiring is used for
256    supervisor programs, not I/O buffers.
257    $err
258 
259    A: $recover
260    $boot_tape
261 
262    Message:
263    wire_proc: lock not locked
264 
265    S: $crash
266 
267    T: $run
268 
269    M: The lock on temp-wiring in the SST was found unlocked at the time
270    an attempt was made to unlock it.  The SST may be damaged.
271    $err
272 
273    A: $recover
274 
275    END MESSAGE DOCUMENTATION */
276      end wire_proc;