1 /****^  ***********************************************************
  2         *                                                         *
  3         * Copyright, (C) Honeywell Bull Inc., 1987                *
  4         *                                                         *
  5         * Copyright, (C) Honeywell Information Systems Inc., 1984 *
  6         *                                                         *
  7         *********************************************************** */
  8 
  9 init_toehold: procedure;
 10 
 11 /* init_toehold.pl1 -- fills in the static data in toehold.alm and saves the
 12    bootload Multics image. */
 13 
 14 /* format: style4,indattr,ifthenstmt,ifthen,idind33,^indcomtxt */
 15 
 16 /* This program is IOM/IMU dependent. */
 17 
 18 /* BIM 11/82 */
 19 /* Modified 8/83 Keith Loepere for absolute mode toehold, saving of "crash" image to disk */
 20 /* Modified 3/84 kpl for saving safe_config_deck */
 21 /* Modified 8/84 Chris Jones for new disk dim. */
 22 /* Modified 10/84 kpl to fix stupid bug in loop limits. */
 23 /* Modified 3/85 Keith Loepere to fix config deck saving now that
 24    move_non_perm_wired_segs works. */
 25 /* Modified 4/85 by RAF to support the larger 3380 disk drives */
 26 
 27 /****^  HISTORY COMMENTS:
 28   1) change(85-09-09,Fawcett), approve(85-09-09,MCR6979),
 29      audit(86-02-13,GDixon), install(86-03-21,MR12.0-1033):
 30      Support IBM FIPS disk drives.
 31   2) change(86-03-12,Fawcett), approve(86-04-11,MCR7383),
 32      audit(86-06-07,GDixon), install(86-07-17,MR12.0-1097):
 33      Add support for subvolumes, MSU3380 and MSU3390.
 34   3) change(87-04-14,Farley), approve(87-07-06,MCR7717),
 35      audit(87-07-13,Lippard), install(87-07-17,MR12.1-1043):
 36      Changed to make sure toehold.seeks_used was set to the higher of the two
 37      dcw lists.
 38                                                    END HISTORY COMMENTS */
 39 
 40 dcl  Config_deck_size                 fixed bin init (4) static options (constant);
 41 dcl  Max_pages_in_segment             fixed bin init (256) static options (constant);
 42 dcl  Pages_per_dcw                    fixed bin init (4) static options (constant);
 43 dcl  Toehold_size                     fixed bin init (2) static options (constant);
 44 dcl  Hardware_low_mem_page_size       fixed bin init (2) static options (constant);
 45 dcl  absadr                           entry (pointer, fixed (35)) returns (fixed bin (26));
 46 dcl  pc$flush                         entry;
 47 dcl  pmut$camp                        entry;
 48 dcl  ptw_util_$make_core              entry (ptr, fixed bin (26));
 49 dcl  save_handler_mc                  entry (ptr);
 50 dcl  sdw_util_$get_address            entry (ptr, fixed bin (26));
 51 dcl  syserr                           entry options (variable);
 52 dcl  syserr$error_code                entry options (variable);
 53 dcl  write_disk$write_disk_no_test    entry (fixed bin, fixed bin (18), ptr, fixed bin (35));
 54 
 55 dcl  abs_seg0$                        (0:255) bit (36 * 1024) aligned external;
 56 dcl  config_deck$                     external;
 57 dcl  dseg$                            (0:2047) fixed bin (71) external aligned;
 58 dcl  emergency_shutdown$              external;
 59 dcl  fault_vector$                    external;
 60 dcl  int_unpaged_page_tables$         external;
 61 dcl  pvt$root_pvtx                    fixed bin external static;
 62 dcl  safe_config_deck$                external;
 63 dcl  sys_boot_info$bce_part_frec      fixed bin external static;
 64 dcl  sys_boot_info$config_part_frec   fixed bin external static;
 65 dcl  sys_boot_info$safe_config_deck_frec fixed bin external static;
 66 dcl  toehold_data$                    external static bit (36) aligned;
 67 
 68 dcl  abs_seg_pt_abs_addr              fixed bin (26);
 69 dcl  code                             fixed bin (35);
 70 dcl  disk_channel_number              fixed bin (7);
 71 dcl  disk_iom_number                  fixed bin (3);
 72 dcl  disk_iom_port_number             fixed bin (3);
 73 dcl  disk_device_number               fixed bin (6);
 74 dcl  fault_vector_abs_addr            fixed bin (26);
 75 dcl  iom_mailbox_abs_addr             fixed bin (26);
 76 dcl  old_memory_state                 fixed bin;
 77 dcl  records_to_do                    fixed bin (18);
 78 dcl  rpv_devt                         fixed bin;
 79 dcl  running_address                  fixed bin;
 80 dcl  running_seeks                    fixed bin;
 81 dcl  running_record                   fixed bin (18);
 82 dcl  sx                               fixed bin;
 83 dcl  toehold_abs_addr                 fixed bin (18);
 84 dcl  toehold_page_addr                fixed bin;
 85 
 86 dcl  abs_seg_pt                       (0:255) bit (36) aligned based (abs_seg_pt_ptr); /* for abs_seg0 */
 87 dcl  abs_seg_pt_ptr                   ptr;
 88 
 89 dcl  1 (seek_idcw_template, data_idcw_template)
 90                                       aligned like idcw;
 91 
 92 dcl  (addr, addrel, currentsize, dimension, divide, hbound, lbound, max, min, mod, ptr, segno, unspec) builtin;
 93 %page;
 94           if sys_boot_info$bce_part_frec = -1
 95                then call syserr (CRASH, "init_toehold: No ""bce"" partition on rpv. Rebuild the RPV to add one.");
 96 
 97           toehold_abs_addr = absadr (addr (toehold$), (0));
 98           toehold_page_addr = divide (toehold_abs_addr, 1024, 17);
 99           toehold_ptr = addr (toehold$);
100           fault_vector_abs_addr = absadr (addr (fault_vector$), (0));
101           iom_mailbox_abs_addr = absadr (addr (iom_mailbox$), (0));
102 
103           sys_boot_info$safe_config_deck_frec = divide (absadr (addr (safe_config_deck$), (0)), 1024, 16)
104                + sys_boot_info$bce_part_frec + CRASH_HANDLER_RECORDX;
105                                                             /* find this before safe_config_deck is moved in memory */
106 
107           toehold.memory_state = 0;                         /* contents invalid */
108 
109           call find_rpv;                                    /* io paths to rpv */
110 
111           toehold.esd_segnum = segno (addr (emergency_shutdown$));
112 
113           unspec (seek_idcw_template) = IDCW_INIT_STRING;
114           seek_idcw_template.command = seek_command (rpv_devt); /* Seek */
115           seek_idcw_template.device = disk_device_number;
116           seek_idcw_template.ext_ctl = "0"b;
117           seek_idcw_template.control = PROCEED;
118           seek_idcw_template.chan_cmd = SINGLE_RECORD;
119           unspec (data_idcw_template) = unspec (seek_idcw_template);
120 
121 /* write command = "31"b3; read command = "25"b3 */
122 
123           data_idcw_template.ext_ctl = "1"b;                /* data is anyplace */
124           data_idcw_template.control = TERMINATE;
125 
126           unspec (toehold.save_dcws) = ""b;
127           unspec (toehold.handler_dcws) = ""b;
128 
129           dcw_list_ptr = addr (toehold.save_dcws);
130           toehold.dcws_per_cyl = divide (rec_per_cyl (rpv_devt) + (Pages_per_dcw - 1), Pages_per_dcw, 17);
131           toehold.seeks_used = 1;                           /* set here so that the dcw_list_size will be correct */
132           toehold.dcw_list_size = currentsize (dcw_list);   /* this is used by toehold */
133           running_seeks = 0;
134           running_address = Hardware_low_mem_page_size;
135           running_record = sys_boot_info$bce_part_frec + SAVED_IMAGE_RECORDX + running_address;
136           records_to_do = toehold_page_addr - running_address;
137 
138 /* don't save, restore iom_mailbox or toehold */
139 
140           do while (records_to_do > 0);
141                running_seeks = running_seeks + 1;
142                call process_one_cylinder (running_seeks, addr (toehold.save_dcws));
143           end;
144 
145           running_address = toehold_page_addr + Toehold_size;
146           running_record = sys_boot_info$bce_part_frec + SAVED_IMAGE_RECORDX + running_address;
147           records_to_do = Max_pages_in_segment + Max_pages_in_segment - running_address;
148 
149           do while (records_to_do > 0);
150                running_seeks = running_seeks + 1;
151                call process_one_cylinder (running_seeks, addr (toehold.save_dcws));
152           end;
153 
154           toehold.seeks_used = running_seeks;               /* remember seeks used for save_dcws */
155 
156 /* now list to read in config deck and handler */
157 
158           running_seeks = 0;
159           running_record = sys_boot_info$config_part_frec;
160           running_address = divide (absadr (addr (config_deck$), (0)), 1024, 18);
161           records_to_do = Config_deck_size;
162 
163           do while (records_to_do > 0);
164                running_seeks = running_seeks + 1;
165                call process_one_cylinder (running_seeks, addr (toehold.handler_dcws));
166           end;
167 
168           running_address = toehold_page_addr + Toehold_size;
169           running_record = sys_boot_info$bce_part_frec + CRASH_HANDLER_RECORDX + running_address;
170           records_to_do = Max_pages_in_segment + Max_pages_in_segment - running_address;
171 
172           do while (records_to_do > 0);
173                running_seeks = running_seeks + 1;
174                call process_one_cylinder (running_seeks, addr (toehold.handler_dcws));
175           end;
176 
177           toehold.seeks_used = max (running_seeks, toehold.seeks_used);
178                                                             /* remember longest of the two lists */
179 %page;
180 
181 /* save fault_vector and iom_mailbox in toehold_data for handler */
182 
183           unspec (addrel (addr (toehold_data$), fault_vector_abs_addr) -> fv) =
184                unspec (addr (fault_vector$) -> fv);
185 
186           unspec (addrel (addr (toehold_data$), iom_mailbox_abs_addr) -> iom_mailbox_seg) =
187                unspec (addr (iom_mailbox$) -> iom_mailbox_seg);
188 
189 /* save "crash" handler to disk */
190 
191           call pc$flush;
192           call sdw_util_$get_address (addr (dseg$ (segno (addr (abs_seg0$)))), abs_seg_pt_abs_addr); /* build segment onto high 256k mem */
193           abs_seg_pt_ptr = ptr (addr (int_unpaged_page_tables$), abs_seg_pt_abs_addr - absadr (addr (int_unpaged_page_tables$), (0)));
194 
195           do running_address = 0 to Max_pages_in_segment - 1;
196                call ptw_util_$make_core (addr (abs_seg_pt (running_address)), (running_address + Max_pages_in_segment) * 1024);
197           end;
198           call pmut$camp;
199 
200           do running_address = Max_pages_in_segment + Max_pages_in_segment - 1 to Max_pages_in_segment by -1; /* save backwards is faster */
201                running_record = sys_boot_info$bce_part_frec + CRASH_HANDLER_RECORDX + running_address;
202                call write_disk$write_disk_no_test (pvt$root_pvtx, running_record, addr (abs_seg0$ (running_address - Max_pages_in_segment)), code);
203                if code ^= 0 then call syserr$error_code (CRASH, code, "init_toehold: Unable to save bootload Multics image to disk.");
204           end;
205 
206           do running_address = 0 to Max_pages_in_segment - 1; /* low mem */
207                call ptw_util_$make_core (addr (abs_seg_pt (running_address)), running_address * 1024);
208           end;
209           call pmut$camp;
210 
211           do running_address = Max_pages_in_segment - 1 to toehold_page_addr + Toehold_size by -1; /* don't save toehold (or what's below it) */
212                running_record = sys_boot_info$bce_part_frec + CRASH_HANDLER_RECORDX + running_address;
213                call write_disk$write_disk_no_test (pvt$root_pvtx, running_record, addr (abs_seg0$ (running_address)), code);
214                if code ^= 0 then call syserr$error_code (CRASH, code, "init_toehold: Unable to save bootload Multics image to disk.");
215           end;
216 
217           call save_handler_mc (addr (toehold$));
218 
219 /* must be done as soon as possible after disk save */
220 
221 /* We get here at two different times.  The first case is when init_toehold
222 was called from real_initializer.  At this time, we simply continue on from
223 this point with filling in the toehold.  In the second case, we have just
224 crashed/shut down, and the toehold has restarted bce.  When restarting bce, it
225 transfers to the last location it knows, which was the last instruction in
226 save_handler_mc, thus returning us here.  In this case, we must quickly get out
227 of here and back to real_initializer, who will know what to do (reinitialize
228 bce).  Thus, this operation is the last thing done here in init_toehold.
229 
230 This whole thing is done since bce must be restarted with the stack history
231 basically intact, since from the reinitialized bce we may want to re-boot
232 Multics, which depends on the normal flow of control, including the sequence
233 of calls leading up to real_initializer. */
234 
235 /* toehold will be declared valid (memory_state set) in real_initializer */
236 
237           return;
238 %page;
239 save_safe_config_deck: entry;
240 
241 /* Save the safe config deck into the crash handler for future possible
242 failure of bce */
243 
244           toehold_ptr = addr (toehold$);
245 
246           old_memory_state = toehold.memory_state;
247           toehold.memory_state = 0;                         /* while finding rpv */
248 
249           call find_rpv;                                    /* find new io paths */
250 
251           toehold.memory_state = old_memory_state;
252 
253           do running_record = sys_boot_info$safe_config_deck_frec + Config_deck_size - 1 to sys_boot_info$safe_config_deck_frec by -1;
254                call write_disk$write_disk_no_test (
255                     pvt$root_pvtx, running_record,
256                     addrel (addr (safe_config_deck$), 1024 * (running_record - sys_boot_info$safe_config_deck_frec)), code);
257                if code ^= 0 then call syserr$error_code (BEEP, code, "init_toehold: Unable to save safe_config_deck to disk.");
258           end;
259           return;
260 %page;
261 process_one_cylinder:
262      procedure (cx, p_dcw_list_ptr);
263 dcl  cx                               fixed bin;            /* dcw_list cylinder index */
264 dcl  p_dcw_list_ptr                   ptr;
265 dcl  full_tallys                      fixed bin;
266 dcl  i                                fixed bin;
267 dcl  records_to_do_here               fixed bin (18);
268 dcl  residue                          fixed bin;
269 
270           dcw_list_ptr = p_dcw_list_ptr;
271           dcw_list (cx).seek_idcw = unspec (seek_idcw_template);
272           data_idcw_template.ext = ext_value (running_address);
273           dcw_list (cx).data_idcw = unspec (data_idcw_template);
274           dcw_list (cx).seek_addresses = sector (running_record);
275           dcw_ptr = addr (dcw_list (cx).seek_dcw);
276           unspec (dcw) = IOTD_INIT_STRING;
277           dcw.address = absadr (addr (dcw_list.seek_addresses (cx)), (0));
278           dcw.tally = 1;
279 
280 /**** First calculate the limit of records we can write into the */
281 /**** current cylinder. This cannot come out 0 */
282 
283           records_to_do_here = min (records_to_do, rec_per_cyl (rpv_devt) - mod (running_record, rec_per_cyl (rpv_devt)));
284 
285 /**** Then correct for the 256K boundary, which occurs when we go from page */
286 /**** 255 to page 256. */
287 
288           if ext_value (running_address) < 1 & ext_value (running_address + records_to_do_here) ^< 1
289                then records_to_do_here = Max_pages_in_segment - running_address; /* if running_addr is 255 (256'th page), do that 1 record */
290 
291 /**** Now fill in the dcws */
292 
293           if mod (records_to_do_here, Pages_per_dcw) = 0
294           then do;
295                full_tallys = divide (records_to_do_here, Pages_per_dcw, 18, 0);
296                residue = 0;
297           end;
298           else do;
299                full_tallys = divide (records_to_do_here, Pages_per_dcw, 18, 0);
300                residue = mod (records_to_do_here, Pages_per_dcw);
301           end;
302 
303           do i = 1 to full_tallys;
304                dcw_ptr = addr (dcw_list (cx).data_dcws (i));
305                unspec (dcw) = IOTP_INIT_STRING;
306                dcw.address = mod (running_address, Max_pages_in_segment) * 1024;
307                dcw.tally = 0;                               /* 4096 */
308                running_address = running_address + Pages_per_dcw;
309                running_record = running_record + Pages_per_dcw;
310           end;
311           if residue = 0
312                then dcw.type = IOTD;                        /* ptr left at last one */
313           else do;
314                dcw_ptr = addr (dcw_list (cx).data_dcws (i));/* i is 1 past */
315                unspec (dcw) = IOTD_INIT_STRING;
316                dcw.address = mod (running_address, Max_pages_in_segment) * 1024;
317                dcw.tally = residue * 1024;
318                running_address = running_address + residue;
319                running_record = running_record + residue;
320           end;
321 
322           records_to_do = records_to_do - records_to_do_here;
323 
324 /***** WHEW --- all set up */
325      end process_one_cylinder;
326 
327 
328 
329 
330 /* rpv_devt is a global parameter of this */
331 
332 sector:
333      procedure (Record) returns (fixed bin (35));
334 dcl  Record                           fixed bin (18);
335 dcl  devadd                           fixed bin (18);
336 dcl  record_offset                    fixed bin (18);
337           if pvte.is_sv then do;
338                                                             /* convert the subvolume devadd to the real devadd */
339 
340                record_offset = mod (Record, pvte.records_per_cyl);
341                devadd = ((Record - record_offset) * pvte.num_of_svs) +
342                     pvte.record_factor + record_offset;
343           end;
344           else devadd = Record;
345           return ((divide (devadd, rec_per_cyl (rpv_devt), 18, 0) * sect_per_cyl (rpv_devt))
346                + (mod (devadd, rec_per_cyl (rpv_devt)) * sect_per_rec (rpv_devt)));
347      end sector;
348 
349 ext_value:
350      procedure (Address) returns (fixed bin);
351 dcl  Address                          fixed bin;
352 
353           return (divide (Address, Max_pages_in_segment, 18, 0));
354      end ext_value;
355 %page;
356 find_rpv: proc;
357 
358 /* find out about rpv, in particular, paths to it */
359 
360           pvt_arrayp = addr (pvt$array);
361           pvtep = addr (pvt_array (pvt$root_pvtx));
362           rpv_devt = pvte.device_type;
363           disk_device_number = pvte.logical_area_number;
364 
365 /* find the main channel to this disk. */
366 
367           disksp = addr (disk_seg$);
368           iom_data_ptr = addr (iom_data$);
369           do sx = 1 to disk_data.subsystems while (disk_data.name (sx) ^= pvte.devname);
370           end;
371           diskp = ptr (disksp, disk_data.offset (sx));
372 
373           do toehold.n_paths_used = 1 to min (dimension (toehold.paths, 1), disktab.nchan);
374                cp = addr (ptr (disksp, disktab.channels) -> disk_channel_table (toehold.n_paths_used));
375                disk_iom_number = iom_data.per_device (chantab.chx).iom;
376                disk_channel_number = iom_data.per_device (chantab.chx).channel;
377 
378                do disk_iom_port_number = lbound (scs$port_data, 1) to hbound (scs$port_data, 1)
379                     while (scs$port_data (disk_iom_port_number).assigned ^= IOM_PORT
380                     | scs$port_data (disk_iom_port_number).iom_number ^= disk_iom_number);
381                end;
382 
383                toehold.paths (toehold.n_paths_used).port_number = disk_iom_port_number;
384                toehold.paths (toehold.n_paths_used).iom_number = disk_iom_number;
385                toehold.paths (toehold.n_paths_used).channel_number = disk_channel_number;
386 
387                pcw_ptr = addr (toehold.paths (toehold.n_paths_used).pcw);
388                unspec (pcw) = PCW_INIT_STRING;
389                pcw.command = "40"b3;                        /* reset status */
390                pcw.device = disk_device_number;
391                pcw.ext = 0;
392           end;
393           toehold.n_paths_used = toehold.n_paths_used - 1;  /* do went 1 too far */
394           return;
395      end;
396 %page; %include dskdcl;
397 %page; %include fault_vector;
398 %page; %include fs_dev_types;
399 %page; %include io_chnl_util_dcls;
400 %page; %include iom_chan_control_words;
401 %page; %include iom_data;
402 %page; %include pvte;
403 %page; %include scs;
404 %page; %include syserr_constants;
405 %page; %include toehold_save_dcls_;
406 %page;
407 /* BEGIN MESSAGE DOCUMENTATION
408 
409    Message:
410    init_toehold: No "bce" partition on rpv. Rebuild the RPV to add one.
411 
412    S: $crash
413 
414    T: $init
415 
416    M:  The partition used to hold the bootload command environment is
417    missing from the rpv.
418 
419    A:  A rebuild of the rpv is necessary.
420 
421    Message:
422    init_toehold: Unable to save bootload Multics image to disk.
423 
424    S: $crash
425 
426    T: $init
427 
428    M: An i/o error prevented the establishment of the bce crash handler.
429 
430    Message:
431    init_toehold: Unable to save safe_config_deck to disk.
432 
433    S: $beep
434 
435    T: $init
436 
437    M: The safe_config_deck, used to re-establish bce when a failure of bce
438    itself occurs, could not be updated to disk.  A future failure of bce may
439    be catastrophic.
440 
441    A: Try performing a reinitialize operation, making sure that the config
442    deck is perfect.
443 
444    END MESSAGE DOCUMENTATION */
445 
446      end init_toehold;