?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Deadstart : Recovery services' ??
MODULE dsm$recovery_services;

{ PURPOSE:
{   This module contains all the routines which allow:
{     1)  Access to the image file.
{     2)  Access to old mainframe wired.
{     3)  Defining the recovery sequence.
{
{ DESIGN:
{   Implementation of access to the image file is done in such a way that the image file could change and
{   not break compatability of systems either forward or backward.  The image file contains 2 parts, the
{   recovery deadstart file (RDF) followed by the memory image.  The RDF contains information organized in
{   such way that forward and backward compatability problems can be resolved.  See the module that
{   contains the routines for RDF access for a better description.  The memory image starts right after the
{   RDF on the image file.  The memory image is written by the boot when a recovery is necessary, the memory
{   image is a copy of that part of memory that is used to deadstart the system.  The SSR contains entries
{   that define the image file.  One entry defines the size of the RDF and another defines the length of the
{   memory image.  By using the values from the RDF or SSR forward and backward compatability among systems
{   is maintained.  Constants define the RDF length and the image length but these are the desired values
{   for this system, not necessarily what is defined.  The size of the image file can be increased by
{   changing the constant and recompiling, the image file will be extended when the system is committed if
{   disk space is available.  If space is not available to extend the image file the system continues running
{   with currently defined image file.  On an installation deadstart the image file is created using the
{   constants to determine its size.  If there is any doubt as to the real image characteristics, get them
{   from the RDF.  On a recovery deadstart the SSR contains the values the boot uses to write the image.  The
{   values in the SSR are obtained from the RDF during system deadstart.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$mainframe_paged_literal
*copyc cml$system_informative_message
*copyc dmc$deadstart_file_alloc_size
*copyc dsc$previous_recovery_type
*copyc dst$deadstart_condition
*copyc dst$deadstart_sequence_steps
*copyc dst$image_file
*copyc dst$image_page_description
*copyc dst$image_status
*copyc dst$list_block
*copyc dst$nve_image_descriptor
*copyc dst$r_pointer
*copyc dst$rb_system_deadstart_status
*copyc dst$recover_deadstart_files
*copyc mmt$rcv_memory_mgr
*copyc osc$processor_defined_registers
*copyc ost$deadstart_phase
?? POP ??
*copyc clp$convert_integer_to_string
*copyc dmp$set_file_limit
*copyc dpp$get_next_line
*copyc dpp$put_next_line
*copyc dpp$put_critical_message
*copyc dsp$build_sequence_p
*copyc dsp$check_saved_passwords
*copyc dsp$close_image_file
*copyc dsp$extend_image_file
*copyc dsp$get_cy2000_element
*copyc dsp$get_data_from_rdf
*copyc dsp$get_data_from_ssr
*copyc dsp$get_entry_from_ssr
*copyc dsp$get_integer_from_rdf
*copyc dsp$log_sys_msg_help
*copyc dsp$open_image_file
*copyc dsp$save_sys_status_current_ds
*copyc dsp$store_data_in_rdf
*copyc dsp$store_data_in_ssr
*copyc dsp$store_entry_in_ssr
*copyc dsp$store_integer_in_rdf
*copyc dsp$store_sys_msg_in_image
*copyc dsp$upgrade_primary_dsfile_mau
*copyc i#build_adaptable_seq_pointer
*copyc i#call_monitor
*copyc i#move
*copyc i#real_memory_address
*copyc mmp$assign_mass_storage
*copyc mmp$build_segment
*copyc mmp$commit_memory
*copyc mmp$define_image_file
*copyc mmp$free_image_pages
*copyc mmp$get_sdtx_entry_p
*copyc mmp$invalidate_segment
*copyc osp$fatal_system_error
*copyc osp$set_status_abnormal
*copyc osp$system_error
*copyc pmp$find_executing_task_xcb
*copyc pmp$get_legible_date_time
*copyc pmp$get_processor_attributes
*copyc pmp$zero_out_table
*copyc syp$display_deadstart_message
*copyc syp$process_deadstart_status
?? EJECT ??
*copyc dmv$display_recovery_messages
*copyc dmv$ds_msg_update_interval
*copyc dpv$system_core_display
*copyc dsv$ignore_image
*copyc dsv$mainframe_type
*copyc dsv$sys_msg_buffer_desc_p
*copyc gfv$null_sfid
*copyc jmv$system_core_id
*copyc mmv$default_sdtx_entry
*copyc mmv$continue_bit_count_p
*copyc mmv$mf_wired_asid_p
*copyc mmv$pft_p
*copyc mmv$pt_length
*copyc osv$180_memory_limits
*copyc osv$mainframe_wired_heap
*copyc osv$page_size
*copyc syv$job_recovery_option
*copyc syv$setsa_job_recovery_option

  VAR
    syv$recovery_override: [XREF] 0 .. 0ff(16);

?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  TYPE
    t$hardware_registers = RECORD
      page_table_address: integer,
      page_table_length: integer,
      page_size: integer,
      mps: integer,
    RECEND;
?? EJECT ??

  VAR
    syv$lower_to_upper: [XDCL, #GATE, READ, oss$mainframe_paged_literal] string (256) := $CHAR (00) CAT
          $CHAR (01) CAT $CHAR (02) CAT $CHAR (03) CAT $CHAR (04) CAT $CHAR (05) CAT $CHAR (06) CAT
          $CHAR (07) CAT $CHAR (08) CAT $CHAR (09) CAT $CHAR (10) CAT $CHAR (11) CAT $CHAR (12) CAT
          $CHAR (13) CAT $CHAR (14) CAT $CHAR (15) CAT $CHAR (16) CAT $CHAR (17) CAT $CHAR (18) CAT
          $CHAR (19) CAT $CHAR (20) CAT $CHAR (21) CAT $CHAR (22) CAT $CHAR (23) CAT $CHAR (24) CAT
          $CHAR (25) CAT $CHAR (26) CAT $CHAR (27) CAT $CHAR (28) CAT $CHAR (29) CAT $CHAR (30) CAT
          $CHAR (31) CAT ' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLM' CAT
          'NOPQRSTUVWXYZ{|}~' CAT $CHAR (127) CAT $CHAR (128) CAT $CHAR (129) CAT $CHAR (130) CAT
          $CHAR (131) CAT $CHAR (132) CAT $CHAR (133) CAT $CHAR (134) CAT $CHAR (135) CAT $CHAR (136) CAT
          $CHAR (137) CAT $CHAR (138) CAT $CHAR (139) CAT $CHAR (140) CAT $CHAR (141) CAT $CHAR (142) CAT
          $CHAR (143) CAT $CHAR (144) CAT $CHAR (145) CAT $CHAR (146) CAT $CHAR (147) CAT $CHAR (148) CAT
          $CHAR (149) CAT $CHAR (150) CAT $CHAR (151) CAT $CHAR (152) CAT $CHAR (153) CAT $CHAR (154) CAT
          $CHAR (155) CAT $CHAR (156) CAT $CHAR (157) CAT $CHAR (158) CAT $CHAR (159) CAT $CHAR (160) CAT
          $CHAR (161) CAT $CHAR (162) CAT $CHAR (163) CAT $CHAR (164) CAT $CHAR (165) CAT $CHAR (166) CAT
          $CHAR (167) CAT $CHAR (168) CAT $CHAR (169) CAT $CHAR (170) CAT $CHAR (171) CAT $CHAR (172) CAT
          $CHAR (173) CAT $CHAR (174) CAT $CHAR (175) CAT $CHAR (176) CAT $CHAR (177) CAT $CHAR (178) CAT
          $CHAR (179) CAT $CHAR (180) CAT $CHAR (181) CAT $CHAR (182) CAT $CHAR (183) CAT $CHAR (184) CAT
          $CHAR (185) CAT $CHAR (186) CAT $CHAR (187) CAT $CHAR (188) CAT $CHAR (189) CAT $CHAR (190) CAT
          $CHAR (191) CAT $CHAR (192) CAT $CHAR (193) CAT $CHAR (194) CAT $CHAR (195) CAT $CHAR (196) CAT
          $CHAR (197) CAT $CHAR (198) CAT $CHAR (199) CAT $CHAR (200) CAT $CHAR (201) CAT $CHAR (202) CAT
          $CHAR (203) CAT $CHAR (204) CAT $CHAR (205) CAT $CHAR (206) CAT $CHAR (207) CAT $CHAR (208) CAT
          $CHAR (209) CAT $CHAR (210) CAT $CHAR (211) CAT $CHAR (212) CAT $CHAR (213) CAT $CHAR (214) CAT
          $CHAR (215) CAT $CHAR (216) CAT $CHAR (217) CAT $CHAR (218) CAT $CHAR (219) CAT $CHAR (220) CAT
          $CHAR (221) CAT $CHAR (222) CAT $CHAR (223) CAT $CHAR (224) CAT $CHAR (225) CAT $CHAR (226) CAT
          $CHAR (227) CAT $CHAR (228) CAT $CHAR (229) CAT $CHAR (230) CAT $CHAR (231) CAT $CHAR (232) CAT
          $CHAR (233) CAT $CHAR (234) CAT $CHAR (235) CAT $CHAR (236) CAT $CHAR (237) CAT $CHAR (238) CAT
          $CHAR (239) CAT $CHAR (240) CAT $CHAR (241) CAT $CHAR (242) CAT $CHAR (243) CAT $CHAR (244) CAT
          $CHAR (245) CAT $CHAR (246) CAT $CHAR (247) CAT $CHAR (248) CAT $CHAR (249) CAT $CHAR (250) CAT
          $CHAR (251) CAT $CHAR (252) CAT $CHAR (253) CAT $CHAR (254) CAT $CHAR (255);

  VAR
    dsv$actual_deadstart_phase: [XDCL, #GATE] ost$deadstart_phase := osc$normal_deadstart,

    { Define variable for recovery deadstart file (RDF) size, must be a multiple of deadstart
    { file allocation size so that data after it can be accessed easily.  This is the image table
    { part of the image file.  This variable is set early in deadstart to the size of the RDF obtained
    { from the RDF.  Using the size from the RDF ensures forward and backward compatability among systems.

    dsv$rdf_size: [XDCL] ost$halfword := 0,
    osv$deadstart_phase: [XDCL, #GATE] ost$deadstart_phase := osc$normal_deadstart,

    v$current_deadstart_step: dst$deadstart_sequence_steps := dsc$dss_start_deadstart_process,
    v$default_sdte: mmt$segment_descriptor := [[osc$vl_regular_segment, osc$non_executable,
          osc$read_uncontrolled, osc$write_uncontrolled, osc$os_ring_1, osc$tsrv_ring, 0,
          [FALSE, FALSE, 0]], 0, 0],
    v$image_file_p: ^SEQ ( * ) := NIL,
    v$image_file_segment: mmt$segment_pointer,
    v$image_file_sfid: gft$system_file_identifier,
    v$image_good: boolean := FALSE,

    { Variable v$list_block will be saved in the RDF when the image is committed.

    v$list_block: dst$list_block := [NIL, NIL, NIL, NIL],

    v$old_load_offset: integer := 0,
    v$old_registers: t$hardware_registers,
    v$rcv_mainframe_wired_segment_p: ^SEQ ( * ) := NIL;
?? OLDTITLE ??
?? NEWTITLE := 'check_recovery_state', EJECT ??

{ PURPOSE:
{   This procedure checks the recovery state by examining variables in the RDF areas and in the SSR.

  PROCEDURE check_recovery_state
    (VAR recovery_needed: boolean;
     VAR system_core_id: ost$name;
     VAR bad_system_core_id: boolean);

    VAR
      boolean_answer_received: boolean,
      good_image_flag: integer,
      idle_status: ost$name,
      ignore_status: ost$status,
      line_received: boolean,
      name_seq_p: ^SEQ ( * ),
      recovery_name: ost$name,
      reply: string (10),
      ssr_image_name: ost$name,
      ssr_seq_p: ^SEQ ( * ),
      system_core_id_seq_p: ^SEQ ( * ),
      uc_reply: string (10);

    name_seq_p := #SEQ (recovery_name);
    dsp$get_data_from_rdf (dsc$rdf_recovery_image_status, dsc$rdf_recovery, name_seq_p);

    name_seq_p := #SEQ (idle_status);
    dsp$get_data_from_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, name_seq_p);

    name_seq_p := #SEQ (ssr_image_name);
    dsp$get_data_from_ssr (dsc$ssr_image_status, name_seq_p);

    { Examine the image file fields to determine the recovery state.

    recovery_needed := TRUE;
    v$image_good := FALSE;

    IF (idle_status = dsc$nve_idled) THEN
      recovery_needed := FALSE;

    ELSEIF (recovery_name = dsc$image_initialized) THEN
      osp$fatal_system_error ('Last initial deadstart did not complete.', NIL);

    ELSEIF (recovery_name = dsc$nve_recovered) THEN

      { The image has already been recovered.

      recovery_needed := FALSE;

      { Check for image lost after recovery but before committment

      IF (ssr_image_name = dsc$ready_to_run) THEN
        dsp$get_integer_from_rdf (dsc$rdf_good_image_flag, dsc$rdf_recovery, good_image_flag);
        v$image_good := (good_image_flag = $INTEGER (TRUE));
      IFEND;

    ELSEIF (recovery_name = dsc$will_commit) AND (ssr_image_name = dsc$ready_to_run) THEN

      { Recovery of the image is required.

      v$image_good := TRUE;
    IFEND;

    IF (NOT v$image_good) AND (syv$recovery_override >= 2) THEN
      dpp$put_next_line (dpv$system_core_display, ' Attention:', ignore_status);
      dpp$put_next_line (dpv$system_core_display, ' Recovery was disabled due to potentially bad image.',
            ignore_status);
      dpp$put_next_line (dpv$system_core_display,
            ' The RECOVERY_OVERRIDE system attribute was set by the operator to override', ignore_status);
      dpp$put_next_line (dpv$system_core_display,
            ' this condition and an attempt will be made to force recovery.', ignore_status);

      dpp$put_next_line (dpv$system_core_display,
            ' Recovering with a bad memory image can cause severe file system damage!', ignore_status);
      dpp$put_next_line (dpv$system_core_display,
            ' Enter YES if you want to continue recovery or NO to disable recovery: ', ignore_status);

      boolean_answer_received := FALSE;
      line_received := FALSE;
      REPEAT
        dpp$get_next_line (dpv$system_core_display, osc$wait, reply, line_received);
        IF line_received THEN
          dpp$put_next_line (dpv$system_core_display, reply, ignore_status);
          #TRANSLATE (syv$lower_to_upper, reply, uc_reply);
          IF (uc_reply = 'Y') OR (uc_reply (1, 3) = 'YES') THEN
            v$image_good := TRUE;
            boolean_answer_received := TRUE;
          ELSEIF (uc_reply = 'N') OR (uc_reply (1, 2) = 'NO') THEN
            syv$recovery_override := 0;
            boolean_answer_received := TRUE;
          ELSE
            dpp$put_next_line (dpv$system_core_display, '--ERROR--  Please enter YES or NO: ', ignore_status);
          IFEND;
        IFEND;
      UNTIL boolean_answer_received;

      IF v$image_good THEN
        dpp$put_next_line (dpv$system_core_display,
              ' Recovery reenabled by RECOVERY_OVERRIDE system attribute.', ignore_status);
      ELSE
        dpp$put_next_line (dpv$system_core_display, ' RECOVERY_OVERRIDE system attribute reset to 0',
              ignore_status);
      IFEND;
    IFEND;

    v$image_good := v$image_good AND NOT dsv$ignore_image;

    system_core_id_seq_p := #SEQ (system_core_id);
    dsp$get_data_from_rdf (dsc$rdf_system_core_id, dsc$rdf_production, system_core_id_seq_p);
    IF recovery_needed THEN
      IF v$image_good AND (system_core_id <> jmv$system_core_id) THEN
        IF syv$recovery_override > 0 THEN
          bad_system_core_id := FALSE;
        ELSE
          v$image_good := FALSE;
          bad_system_core_id := TRUE;
        IFEND;
      ELSE
        bad_system_core_id := FALSE;
      IFEND;
    IFEND;

  PROCEND check_recovery_state;
?? OLDTITLE ??
?? NEWTITLE := 'commit_image', EJECT ??

{ PURPOSE:
{   This procedure sets various values in the RDF and SSR for writing the next image file and recovering
{   this instance of the system if necessary.

  PROCEDURE commit_image;

    VAR
      convert_iht:  RECORD
        CASE boolean OF
        = FALSE=
          iht_p: ^mmt$old_modified_bits,
        = TRUE =
          cbc_p: ^mmt$continue_bit_count,
        CASEND,
      RECEND,
      hash_table_data: dst$r_pointer,
      name_stored: ost$name,
      rcv_memory_mgr_info: mmt$rcv_memory_mgr,
      registers: t$hardware_registers,
      rma: integer;

    dsp$store_integer_in_rdf (dsc$rdf_good_image_flag, dsc$rdf_recovery, $INTEGER (FALSE));

    name_stored := dsc$nve_recovered;
    dsp$store_data_in_rdf (dsc$rdf_recovery_image_status, dsc$rdf_recovery, #SEQ (name_stored));

    dsp$store_integer_in_rdf (dsc$rdf_lower_memory_limit, dsc$rdf_production, osv$180_memory_limits.lower);

    registers.page_table_address := #READ_REGISTER (osc$pr_page_table_address);
    registers.page_size := osv$page_size;
    registers.page_table_length := (#READ_REGISTER (osc$pr_page_table_length) + 1) * 4096;
    registers.mps := #READ_REGISTER (osc$pr_monitor_process_state);
    dsp$store_data_in_rdf (dsc$rdf_register_values, dsc$rdf_production, #SEQ (registers));

    { Initialize the R pointer for writing the page table modify bit map during recovery deadstarts.
    { The page table modify bit map is written over the 'continue bit count' table which is not needed
    { for recovery.  This table must be contiguous memory and large enough to hold the modify bit for
    { each page table entry, 64 modify bits per word.  The modify bit map is generated by a PP at
    { deadstart time.  Set the length in words.

    i#real_memory_address (mmv$continue_bit_count_p, rma);
    hash_table_data.offset := (rma DIV 10(8)) MOD 100(8);
    hash_table_data.rupper := rma DIV 10000000(8);
    hash_table_data.rlower := (rma DIV 1000(8)) MOD 10000(8);
    IF (#SIZE (mmv$continue_bit_count_p^)) >= (mmv$pt_length DIV 8) THEN
      hash_table_data.length := mmv$pt_length DIV (8 * 8);
    ELSE
      osp$system_error ('The table for page table modify bit map is not large enough.', NIL);
    IFEND;
    dsp$store_data_in_ssr (dsc$ssr_modify_bit_map_pt, #SEQ (hash_table_data));

    rcv_memory_mgr_info.pft_p := mmv$pft_p;
    i#real_memory_address (mmv$pft_p, rcv_memory_mgr_info.pft_p_rma);
    rcv_memory_mgr_info.mfw_asid_p := mmv$mf_wired_asid_p;
    i#real_memory_address (mmv$mf_wired_asid_p, rcv_memory_mgr_info.mfw_asid_p_rma);
    convert_iht.cbc_p := mmv$continue_bit_count_p;
    rcv_memory_mgr_info.iht_p := convert_iht.iht_p;
    i#real_memory_address (mmv$continue_bit_count_p, rcv_memory_mgr_info.iht_p_rma);
    dsp$store_data_in_rdf (dsc$rdf_page_table_modified_bit, dsc$rdf_production, #SEQ (rcv_memory_mgr_info));

    dsp$store_data_in_rdf (dsc$rdf_list_block, dsc$rdf_production, #SEQ (v$list_block));

    name_stored := dsc$will_commit;
    dsp$store_data_in_rdf (dsc$rdf_recovery_image_status, dsc$rdf_recovery, #SEQ (name_stored));
    dsp$store_data_in_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, #SEQ (name_stored));
    dsp$store_data_in_ssr (dsc$ssr_image_status, #SEQ (name_stored));

  PROCEND commit_image;
?? OLDTITLE ??
?? NEWTITLE := 'fetch_pvas_of_image_mfw', EJECT ??

{ PURPOSE:
{   This procedure fetches pages for the OLD mainframe wired segment.

  PROCEDURE fetch_pvas_of_image_mfw
    (    last_image_p: ^cell;
     VAR image_page_description: dst$image_page_description;
     VAR overflow: boolean);

    VAR
      current_asid: ost$asid,
      description_size: integer,
      found_last_pva: boolean,
      image_descriptor: dst$nve_image_descriptor,
      image_iht_p: ^mmt$old_modified_bits,
      image_p: ^cell,
      image_pft_p: ^mmt$page_frame_table,
      index: integer,
      new_asid: ost$asid,
      page_count: integer,
      page_index: integer,
      pages_found: integer,
      pages_saved: integer,
      segment_number: integer,
      segment_offset: integer;

    IF NOT v$image_good THEN
      osp$system_error ('Attempting to use the bad image.', NIL);
    IFEND;

    { Get the image description.

    dsp$get_nve_image_description (image_descriptor);
    page_count := 0;
    current_asid := image_descriptor.rcv_mfw_asid_p^.current;
    IF image_descriptor.rcv_mfw_asid_p^.new <> 0 THEN
      new_asid := image_descriptor.rcv_mfw_asid_p^.new;
    ELSE
      new_asid := current_asid;
    IFEND;
    image_page_description.pagesize := image_descriptor.rcv_page_size;
    image_pft_p := image_descriptor.rcv_page_frame_tbl_p;
    image_iht_p := image_descriptor.rcv_hash_tbl_p;

    FOR index := LOWERBOUND (image_pft_p^) TO UPPERBOUND (image_pft_p^) DO
      IF (image_pft_p^ [index].sva.asid = current_asid) OR (image_pft_p^ [index].sva.asid = new_asid) THEN
        page_count := page_count + 1;
      IFEND;
    FOREND;

    { Determine if there are any pages with the current asid.

    IF (page_count = 0) OR ((current_asid = 0) AND (new_asid = 0)) THEN
      overflow := FALSE;
      image_page_description.valid_desc_count := 0;
      RETURN;
    IFEND;

    { Record the page pva's.

    description_size := UPPERBOUND (image_page_description.page_desc) -
          LOWERBOUND (image_page_description.page_desc) + 1;
    page_index := LOWERBOUND (image_page_description.page_desc);
    pages_found := 0;
    pages_saved := 0;
    segment_number := #SEGMENT (v$image_file_p);
    found_last_pva := FALSE;

  /search_ptbl/
    FOR index := LOWERBOUND (image_pft_p^) TO UPPERBOUND (image_pft_p^) DO
      IF (image_pft_p^ [index].sva.asid = current_asid) OR (image_pft_p^ [index].sva.asid = new_asid) THEN
        pages_found := pages_found + 1;
        segment_offset := image_pft_p^ [index].sva.offset;
        image_p := #ADDRESS (1, segment_number, ((image_descriptor.rcv_page_size * index) -
              image_descriptor.rcv_load_offset) + dsv$rdf_size);
        IF (last_image_p <> NIL) AND (NOT found_last_pva) THEN
          IF last_image_p = image_p THEN
            found_last_pva := TRUE;
          IFEND;
          CYCLE /search_ptbl/;
        IFEND;
        pages_saved := pages_saved + 1;
        image_page_description.page_desc [page_index].image_pva := image_p;
        image_page_description.page_desc [page_index].file_offset := segment_offset;
        image_page_description.page_desc [page_index].page_lock := mmc$lp_not_locked;
        image_page_description.page_desc [page_index].modified := image_iht_p^ [image_pft_p^ [index].pti];

        { Set false just for now...

        image_page_description.page_desc [page_index].page_frame_flawed := FALSE;
        image_page_description.page_desc [page_index].disk_file_error := FALSE;
        page_index := page_index + 1;
        IF pages_saved >= description_size THEN
          EXIT /search_ptbl/;
        IFEND;
      IFEND;
    FOREND /search_ptbl/;

    image_page_description.valid_desc_count := pages_saved;
    overflow := (pages_found < page_count);

  PROCEND fetch_pvas_of_image_mfw;
?? OLDTITLE ??
?? NEWTITLE := 'set_image_recovered', EJECT ??
  PROCEDURE set_image_recovered;

    VAR
      name_stored: ost$name;

    dsp$store_integer_in_rdf (dsc$rdf_good_image_flag, dsc$rdf_recovery, $INTEGER (v$image_good));
    name_stored := dsc$nve_recovered;
    dsp$store_data_in_rdf (dsc$rdf_recovery_image_status, dsc$rdf_recovery, #SEQ (name_stored));
    dsp$store_data_in_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, #SEQ (name_stored));

  PROCEND set_image_recovered;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$advance_deadstart_sequence', EJECT ??

{  PURPOSE:
{    This procedure controls and records the steps of deadstart and recovery.  This procedure receives as
{    input the step to which deadstart is advancing.  Some steps have specific actions that must be taken
{    as part of advancing to that step.  An entry in the SSR and the RDF area contains the present
{    deadstart state.

  PROCEDURE [XDCL, #GATE] dsp$advance_deadstart_sequence
    (    next_deadstart_step: dst$deadstart_sequence_steps);

    VAR
      deadstart_step: dst$ssr_entry,
      deadstart_type: dst$ssr_entry,
      descriptor: dst$nve_image_descriptor,
      ignore_status: ost$status,
      image_size: integer,
      image_state: dst$ssr_entry,
      image_status: ost$name,
      integer_string: ost$string,
      job_recovery_status: string (8),
      message: string (70),
      message_seq_p: ^SEQ ( * ),
      processor_attributes: pmt$processor_attributes,
      rb: dst$rb_system_deadstart_status,
      ssr_image_length: dst$ssr_entry,
      ssr_image_offset: dst$ssr_entry,
      status: ost$status;

    v$current_deadstart_step := next_deadstart_step;
    CASE v$current_deadstart_step OF
    = dsc$dss_ssr_built =

    = dsc$dss_dcfile_read =
      syp$display_deadstart_message ('System core initialization in progress ...');

    = dsc$dss_install_templates =
      syp$display_deadstart_message ('System core loading job template ...');

    = dsc$dss_templates_installed =
      syp$display_deadstart_message ('Loading of job template completed ...');

    = dsc$dss_outward_call_to_jt =
      syp$display_deadstart_message ('System core initiating job template ...');

    = dsc$dss_job_template_started =
      syp$display_deadstart_message ('Job template initiated ...');

    = dsc$dss_ssr_committed =

      { Save data for recovery.

      pmp$get_processor_attributes (processor_attributes, status);
      IF NOT status.normal THEN
        osp$system_error ('Errors in getting processor attributes', ^status);
      IFEND;
      dsp$store_list_block (dsc$processor_attributes, #SEQ (processor_attributes));
      dsp$store_list_block (dsc$system_messages_buffer, #SEQ (dsv$sys_msg_buffer_desc_p));

    = dsc$dss_load_sitecp =
      syp$display_deadstart_message ('Loading configuration prologs ...');

    = dsc$dss_sitecp_loaded =
      syp$display_deadstart_message ('Loading of the configuration prologs completed ...');

    = dsc$dss_load_dstape_libraries =
      syp$display_deadstart_message ('Loading the deadstart files ...');

    = dsc$dss_dstape_libraries_loaded =
      syp$display_deadstart_message ('Loading of the deadstart files completed ...');

    = dsc$dss_recover_mainframe =
      syp$display_deadstart_message ('System recovering mainframe ...');

      IF dsv$actual_deadstart_phase = osc$recovery_deadstart THEN
        IF dsv$ignore_image THEN
          dsp$save_sys_status_current_ds (dsc$ssr_sds_sdas_ignore_image);
        ELSE
          dsp$get_nve_image_description (descriptor);
          IF descriptor.rcv_mainframe_wired_segment <> NIL THEN
            dsp$save_sys_status_current_ds (dsc$ssr_sds_sdas_with_image);
          ELSE
            dsp$save_sys_status_current_ds (dsc$ssr_sds_sdas_without_image);
          IFEND;
        IFEND;
        dsp$store_sys_msg_in_image;
      IFEND;

    = dsc$dss_mainframe_recovered =
      syp$display_deadstart_message ('Recovering of mainframe completed ...');

    = dsc$dss_recovery_completed =

      { Cleanup the image file after recovery.

      IF (osv$deadstart_phase = osc$recovery_deadstart) THEN
        osv$deadstart_phase := osc$normal_deadstart;
        set_image_recovered;
      IFEND;
      dsp$get_entry_from_ssr (dsc$ssr_deadstart_type, deadstart_type);
      IF deadstart_type.right_slot = $INTEGER (dsc$recovery_deadstart) THEN
        deadstart_type.right_slot := $INTEGER (dsc$deadstart_condition_empty);
        dsp$store_entry_in_ssr (dsc$ssr_deadstart_type, dsc$ssr_right_slot, deadstart_type);
      IFEND;

    = dsc$dss_system_committed =
      dsp$check_saved_passwords;

      commit_image;

      { Enable future job recoverys.

      job_recovery_status := 'enable';
      dsp$store_data_in_rdf (dsc$rdf_job_recovery, dsc$rdf_production, #SEQ (job_recovery_status));
      dsp$store_data_in_rdf (dsc$rdf_system_core_id, dsc$rdf_production, #SEQ (jmv$system_core_id));

      { Call memory manager to free all image pages and to inform it that all of memory, as defined by
      { osv$180_memory_limits, can now be used by the system.  Image file page faults will no longer be
      { special cased.  Image file page faults will be processed just like any other segment.

      mmp$free_image_pages;
      mmp$commit_memory;

      { If image length of this system is greater than image length of previous systems extend the image file.

      dsp$get_entry_from_ssr (dsc$ssr_image_length, ssr_image_length);

      IF ssr_image_length.whole_slot < dsc$image_size THEN
        dsp$get_entry_from_ssr (dsc$ssr_image_offset, ssr_image_offset);

        { Set size of the RDF to a multiple of the allocation size.

        dsv$rdf_size := #SIZE (dst$recover_deadstart_files);
        IF (#SIZE (dst$recover_deadstart_files) MOD dmc$deadstart_file_alloc_size) > 0 THEN
          dsv$rdf_size := dsv$rdf_size + dmc$deadstart_file_alloc_size -
                (#SIZE (dst$recover_deadstart_files) MOD dmc$deadstart_file_alloc_size);
        IFEND;

        { The first time the image file was extended the size of the RDF was set to its real value and not
        { padded.  The following check is to allow this first image file extension with padding of the RDF
        { removed.  When standalone deadstart was implemented the RDF was set to twice its real size.

        IF (ssr_image_offset.whole_slot <> dsc$old_rdf_size) THEN
          IF (ssr_image_offset.whole_slot <> dsv$rdf_size) THEN

            { The size of the RDF increased.  This should not happen unless deliberately done.  At that time
            { code must be added to move the old RDF contents after image file expanded.

            osp$system_error ('Size of RDF changed.', NIL);
          IFEND;
        IFEND;

        dsp$close_image_file (v$image_file_sfid, v$image_file_segment);
        dsp$extend_image_file (dsv$rdf_size + dsc$image_size, dsv$rdf_size + ssr_image_length.whole_slot,
              status);
        dsp$open_image_file (v$image_file_sfid, v$image_file_segment, v$image_file_p);

        IF status.normal THEN
          message := ' Image File extended to ';
          clp$convert_integer_to_string ((dsv$rdf_size + dsc$image_size) DIV 100000(16), 10, TRUE,
                integer_string, ignore_status);
          message (25, integer_string.size) := integer_string.value (1, integer_string.size);
          message (25 + integer_string.size, 8) := ' MBytes.';
          syp$display_deadstart_message (message);

          { Update image values in the RDF and SSR.

          dsp$store_integer_in_rdf (dsc$rdf_image_size, dsc$rdf_production, dsc$image_size);
          dsp$store_integer_in_rdf (dsc$rdf_image_table_size, dsc$rdf_production, dsv$rdf_size);
          dsp$update_image_values_in_ssr;
        ELSE

          { Unable to extend image file, log this fact in system log and display a message.

          message := '--WARNING-- Unable to extend image file to ';
          clp$convert_integer_to_string ((dsv$rdf_size + dsc$image_size) DIV 100000(16), 10, TRUE,
                integer_string, ignore_status);
          message (44, integer_string.size) := integer_string.value (1, integer_string.size);
          message (44 + integer_string.size, 11) := ' megabytes.';
          message_seq_p := #SEQ (message);
          dsp$log_sys_msg_help (cml$system_informative_message, message_seq_p);
          syp$display_deadstart_message (message);

          IF osv$180_memory_limits.upper > 8000000(16) THEN

            { If running with more than 128 megabytes of memory this is a fatal error.

            syp$display_deadstart_message (
                  '  Running with more than 128 megabytes of memory and could not extend image');
            syp$display_deadstart_message (
                  '  file.  Deadstart again with 128 megabytes or less of memory and free up');
            syp$display_deadstart_message (
                  '  enough space on system device to expand image file.  Can not run with more');
            syp$display_deadstart_message (
                  '  than 128 megabytes of memory and recover the system with current image file.');
            syp$display_deadstart_message (
                  '  Deadstart with 128 megabytes of memory or less and fix problem.');
            osp$fatal_system_error ('Unable to extend the image file.', ^status);
          IFEND;
        IFEND;
      IFEND;

      deadstart_type.right_slot := $INTEGER (dsc$recovery_deadstart);
      dsp$store_entry_in_ssr (dsc$ssr_deadstart_type, dsc$ssr_right_slot, deadstart_type);

      { Set the image status name in the SSR to ready_to_run AND the image state in the SSR to 0 to request
      { that an image file be written for recovery purposes.  These two steps must be done in this order and
      { one RIGHT after the other to insure the validity of the image file.  A window of error still exists
      { when using this method.  If the system were to crash after ready_to_run was set but before the image
      { state is set to 0, then the problem could exist where VCB does not write the image file but the system
      { believes it has been written.  Perhaps a new method should be used.

      image_status := dsc$ready_to_run;
      dsp$store_data_in_ssr (dsc$ssr_image_status, #SEQ (image_status));
      image_state.whole_slot := 0;
      dsp$store_entry_in_ssr (dsc$ssr_image_state, dsc$ssr_whole_slot, image_state);

      rb.reqcode := syc$rc_system_deadstart_status;
      rb.action := dsc$rb_sds_set_bct_flag;
      rb.bct_flags := dsc$rb_sds_bct_point_of_commit;
      i#call_monitor (#LOC (rb), #SIZE (rb));

      dsp$close_image_file (v$image_file_sfid, v$image_file_segment);
      IF v$rcv_mainframe_wired_segment_p <> NIL THEN
        mmp$invalidate_segment (#SEGMENT (v$rcv_mainframe_wired_segment_p), 1, NIL, status);
      IFEND;
      syp$display_deadstart_message ('System committed ...');

    ELSE

      { do nothing

    CASEND;

    { When deadstart reaches the step where the image file has been accessed to determine the status of
    { NOS/VE as a result of the last termination of NOS/VE, then the step of the current deadstart
    { sequence can be maintained in the image file/recovery segment in rdf_recovery's entry
    { dsc$rdf_deadstart_state.

    IF v$current_deadstart_step >= dsc$dss_image_retrieved THEN
      dsp$store_integer_in_rdf (dsc$rdf_deadstart_state, dsc$rdf_recovery,
            $INTEGER(v$current_deadstart_step));
    IFEND;

    { Save the step of the current deadstart sequence in the SSR.

    deadstart_step.left_slot := $INTEGER (v$current_deadstart_step);
    dsp$store_entry_in_ssr (dsc$ssr_deadstart_state, dsc$ssr_left_slot, deadstart_step);

  PROCEND dsp$advance_deadstart_sequence;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$fetch_list_block', EJECT ??

{ PURPOSE:
{   This procedure fetches a list block from the SSR.

  PROCEDURE [XDCL, #GATE] dsp$fetch_list_block
    (    list_type: dst$list_block_kind;
     VAR list_p: ^SEQ (*));

    VAR
      adj_list_array_p: ^dst$list_for_block,
      first_time: [STATIC] boolean := TRUE,
      list_array: [STATIC] dst$list_for_block,
      list_array_index: dst$list_block_kind,
      list_array_p: ^dst$list_for_block,
      list_block: dst$list_block,
      list_block_p: ^SEQ ( * ),
      list_block_seq_p: ^SEQ ( * );

    IF NOT v$image_good THEN
      osp$system_error ('Attempting to use bad image.', NIL);
    IFEND;

    IF first_time THEN
      list_block_seq_p := #SEQ (list_block);
      dsp$get_data_from_rdf (dsc$rdf_list_block, dsc$rdf_production, list_block_seq_p);
      list_block_p := list_block.list_block_p;
      i#build_adaptable_seq_pointer (#RING (v$rcv_mainframe_wired_segment_p),
            #SEGMENT (v$rcv_mainframe_wired_segment_p), #OFFSET (list_block_p), #SIZE (list_block_p^),
            0, list_block_p);
      RESET list_block_p;
      NEXT list_array_p IN list_block_p;
      adj_list_array_p := #ADDRESS (#RING (v$rcv_mainframe_wired_segment_p),
            #SEGMENT (v$rcv_mainframe_wired_segment_p), #OFFSET (list_array_p));
      FOR list_array_index := LOWERBOUND (list_array) TO UPPERBOUND (list_array) DO
        list_array [list_array_index] := adj_list_array_p^ [list_array_index];
      FOREND;
      first_time := FALSE;
    IFEND;

    list_p := list_array [list_type];
    IF list_p = NIL THEN
      osp$system_error ('Requested list block does not exist.', NIL);
    IFEND;

  PROCEND dsp$fetch_list_block;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_flaw_map', EJECT ??

{ PURPOSE:
{   This procedure makes a request to the service processor to retrieve the flaw map.
{   A NIL pointer is returned if problems are encountered in retrieving the flaw map.

  PROCEDURE [XDCL] dsp$get_flaw_map
    (VAR flaw_map_p: ^ARRAY [1 .. *] OF mmt$page_frame_index);

    VAR
      element_seq_p: ^SEQ ( * ),
      local_status: ost$status,
      memory_element: dst$dft_get_memory_element;

    flaw_map_p := NIL;
    IF dsv$mainframe_type <> dsc$mt_2000_mainframe THEN
      RETURN;
    IFEND;

    { Retrieve the flaw table length.

    element_seq_p := #SEQ (memory_element);
    RESET element_seq_p;
    dsp$get_cy2000_element (dsc$dftb_eid_memory_element, dsc$dft_sub_none, element_seq_p,
          local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    IF memory_element.flaw_table_length <= 0 THEN
      RETURN;
    IFEND;

    ALLOCATE flaw_map_p: [1 .. (memory_element.flaw_table_length * 2)] IN osv$mainframe_wired_heap^;
    pmp$zero_out_table (^flaw_map_p^, #SIZE (flaw_map_p^));

    element_seq_p := #SEQ (flaw_map_p^);
    RESET element_seq_p;
    dsp$get_cy2000_element (dsc$dftb_eid_memory_element, dsc$dft_sub_flaw_table, element_seq_p,
          local_status);
    IF NOT local_status.normal THEN
      FREE flaw_map_p IN osv$mainframe_wired_heap^;
    IFEND;

  PROCEND dsp$get_flaw_map;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_nve_image_description', EJECT ??

{ PURPOSE:
{   This procedure fetches a description of the image file.

  PROCEDURE [XDCL, #GATE] dsp$get_nve_image_description
    (VAR descriptor: dst$nve_image_descriptor);

    VAR
      ignore_data_seq_p: ^SEQ ( * ),
      iht_p: ^mmt$old_modified_bits,
      mfw_asid_p: ^mmt$mainframe_wired_asid,
      pft_p: ^mmt$page_frame_table,
      rcv_memory_mgr_info: mmt$rcv_memory_mgr,
      rcv_memory_mgr_info_seq_p: ^SEQ ( * );

    IF v$image_good THEN
      descriptor.rcv_jps := v$old_registers.mps;
      descriptor.rcv_system_job_mtr_jps := v$old_registers.mps;
      descriptor.rcv_page_size := v$old_registers.page_size;
      descriptor.rcv_load_offset := v$old_load_offset;
      descriptor.nve_image := v$image_file_p;
      descriptor.rcv_mainframe_wired_segment := v$rcv_mainframe_wired_segment_p;

      rcv_memory_mgr_info_seq_p := #SEQ (rcv_memory_mgr_info);
      dsp$get_data_from_rdf (dsc$rdf_page_table_modified_bit, dsc$rdf_production, rcv_memory_mgr_info_seq_p);

      RESET v$image_file_p;
      NEXT ignore_data_seq_p: [[REP (rcv_memory_mgr_info.pft_p_rma - v$old_load_offset) OF cell]]
            IN v$image_file_p;
      NEXT pft_p: [LOWERBOUND (rcv_memory_mgr_info.pft_p^) .. UPPERBOUND (rcv_memory_mgr_info.pft_p^)]
            IN v$image_file_p;
      descriptor.rcv_page_frame_tbl_p := pft_p;

      RESET v$image_file_p;
      NEXT ignore_data_seq_p: [[REP (rcv_memory_mgr_info.iht_p_rma - v$old_load_offset) OF cell]]
            IN v$image_file_p;
      NEXT iht_p: [LOWERBOUND (rcv_memory_mgr_info.iht_p^) .. UPPERBOUND (rcv_memory_mgr_info.iht_p^)]
            IN v$image_file_p;
      descriptor.rcv_hash_tbl_p := iht_p;

      RESET v$image_file_p;
      NEXT ignore_data_seq_p: [[REP (rcv_memory_mgr_info.mfw_asid_p_rma - v$old_load_offset) OF cell]]
            IN v$image_file_p;
      NEXT mfw_asid_p IN v$image_file_p;
      descriptor.rcv_mfw_asid_p := mfw_asid_p;

    ELSE
      descriptor.nve_image := NIL;
      descriptor.rcv_mainframe_wired_segment := NIL;
    IFEND;

  PROCEND dsp$get_nve_image_description;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$idle_system', EJECT ??

{ PURPOSE:
{   This procedure idles the system as far as deadstart is concerned.

  PROCEDURE [XDCL, #GATE] dsp$idle_system
    (    allow_system_commit: boolean);

    VAR
      commit_new_dsfile: integer,
      deadstart_step: dst$ssr_entry,
      deadstart_type: dst$ssr_entry,
      image_state: dst$ssr_entry,
      local_status: ost$status,
      name_stored: ost$name;

    IF allow_system_commit THEN

      { Upgrade to a new disk deadstart file, if necessary.

      dsp$get_integer_from_rdf (dsc$rdf_commit_new_dsfile_flag, dsc$rdf_production, commit_new_dsfile);
      IF commit_new_dsfile = $INTEGER (TRUE) THEN
        dsp$upgrade_primary_dsfile_mau (local_status);
        IF NOT local_status.normal THEN
          syp$display_deadstart_message
                ('The following error occurred while attempting to commit the new system:');
          syp$process_deadstart_status ('Unable to commit new system', FALSE, local_status);
          syp$display_deadstart_message ('The new system was NOT committed.');
        ELSE
          dsp$store_integer_in_rdf (dsc$rdf_commit_new_dsfile_flag, dsc$rdf_production, $INTEGER(FALSE));
          dpp$put_critical_message ('New system has been committed.', local_status);
          syp$display_deadstart_message ('New system has been committed.');
        IFEND;
      IFEND;
    IFEND;

    name_stored := dsc$ready_to_run;
    dsp$store_data_in_ssr (dsc$ssr_image_status, #SEQ (name_stored));
    set_image_recovered;

    deadstart_type.right_slot := $INTEGER (dsc$deadstart_condition_empty);
    dsp$store_entry_in_ssr (dsc$ssr_deadstart_type, dsc$ssr_right_slot, deadstart_type);
    deadstart_step.left_slot := $INTEGER (dsc$dss_recovery_completed);
    dsp$store_entry_in_ssr (dsc$ssr_deadstart_state, dsc$ssr_left_slot, deadstart_step);

    name_stored := dsc$nve_idled;
    dsp$store_data_in_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, #SEQ (name_stored));

    dsp$advance_deadstart_sequence (dsc$dss_system_idled);

    { Set the flag to indicate that an image file does not need to be written.

    image_state.whole_slot := 2;
    dsp$store_entry_in_ssr (dsc$ssr_image_state, dsc$ssr_whole_slot, image_state);

  PROCEND dsp$idle_system;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$recover_mf_wired', EJECT ??

{ PURPOSE:
{   This procedure recovers old mainframe wired on a recovery deadstart.

  PROCEDURE [XDCL, #GATE] dsp$recover_mf_wired;

    CONST
      second = 1000000;

    CONST
      page_count = 9;

    VAR
      assign_backing_store_status: ost$status, {no longer static - it's only in a full dump anyway ...
      base: integer,
      clock: integer,
      date: ost$date,
      destination_p: ^cell,
      display_update_interval: integer,
      idle_status: ost$name,
      idle_status_seq_p: ^SEQ ( * ),
      image_description_p: ^dst$image_page_description,
      largest_rcv_mfw_file_offset: ost$segment_offset,
      last_image_p: ^cell,
      local_status: ost$status,
      max_segment_length: ost$segment_length,
      msg_string: string (81),
      msg_string_length: integer,
      new_wired_segment_number: integer,
      overflow: boolean,
      pages: integer,
      recovery_mainframe_wired_p: ^cell,
      register_seq_p: ^SEQ ( * ),
      sdtx_entry_p: ^mmt$segment_descriptor_extended,
      segment_attributes: mmt$segment_attrib_descriptor,
      segment_number: ost$segment,
      segment_pointer: mmt$segment_pointer,
      status: ost$status,
      time: ost$time,
      valid_count: integer,
      xcb_p: ^ost$execution_control_block;

    pmp$find_executing_task_xcb (xcb_p);
    { Determine if it is necessary to recover old mainframe wired.

    idle_status_seq_p := #SEQ (idle_status);
    dsp$get_data_from_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, idle_status_seq_p);
    IF NOT (v$image_good AND (idle_status <> dsc$nve_idled)) THEN
      RETURN;
    IFEND;

    syp$display_deadstart_message ('  Recovering Mainframe Wired.');
    dsp$get_integer_from_rdf (dsc$rdf_lower_memory_limit, dsc$rdf_production, v$old_load_offset);
    register_seq_p := #SEQ (v$old_registers);
    dsp$get_data_from_rdf (dsc$rdf_register_values, dsc$rdf_production, register_seq_p);

    { Make the recovery segment.

    segment_attributes.validating_ring_number := 1;
    segment_attributes.file_limits_to_enforce := sfc$no_limit;
    PUSH segment_attributes.user_attributes: [1..1];
    segment_attributes.user_attributes^ [1].keyword := mmc$kw_ring_numbers;
    segment_attributes.user_attributes^ [1].r1 := 1;
    segment_attributes.user_attributes^ [1].r2 := 3;
    segment_attributes.sfid := gfv$null_sfid;
    mmp$build_segment (segment_attributes, NIL {shared_taskids}, segment_pointer, status);
    IF NOT status.normal THEN
      osp$system_error ('Error in making recovery segment.', ^status);
    IFEND;
    recovery_mainframe_wired_p := segment_pointer.cell_pointer;
    new_wired_segment_number := #SEGMENT (recovery_mainframe_wired_p);
    sdtx_entry_p := mmp$get_sdtx_entry_p (xcb_p, new_wired_segment_number);
    sdtx_entry_p^.open_validating_ring_number := 0;
    pages := 0;
    last_image_p := NIL;
    overflow := FALSE;
    PUSH image_description_p: [0 .. page_count];
    largest_rcv_mfw_file_offset := 0;

    base := 0;
    display_update_interval := dmv$ds_msg_update_interval * second;

    REPEAT
      IF dmv$display_recovery_messages THEN
        clock := #FREE_RUNNING_CLOCK (0);
        IF clock > (base + display_update_interval) THEN
          base := clock;
          pmp$get_legible_date_time (osc$mdy_date, date, osc$hms_time, time, local_status);

          STRINGREP (msg_string, msg_string_length, '   .. Wired Pages Recovered:   ', pages: 7, '   ',
                time.hms);
          syp$display_deadstart_message (msg_string (1, msg_string_length));
        IFEND;
      IFEND;

      fetch_pvas_of_image_mfw (last_image_p, image_description_p^, overflow);
      IF image_description_p^.valid_desc_count > 0 THEN
        FOR valid_count := 0 TO image_description_p^.valid_desc_count - 1 DO
          pages := pages + 1;
          last_image_p := image_description_p^.page_desc [valid_count].image_pva;
          destination_p := #ADDRESS (1, new_wired_segment_number,
                image_description_p^.page_desc [valid_count].file_offset);
          IF (image_description_p^.page_desc [valid_count].page_lock <> mmc$lp_not_locked) OR
                image_description_p^.page_desc [valid_count].disk_file_error OR
                image_description_p^.page_desc [valid_count].page_frame_flawed THEN
            osp$system_error ('Error in recovering old mainframe wired data.', NIL);
          IFEND;

          { Assign backing store to the recovered mainframe wired segment.  Status is being ignored
          { but saved in a static variable if it is abnormal.  It is only critical that backing store
          { be assigned to this segment now if we run out of memory.

          i#move (last_image_p, destination_p, image_description_p^.pagesize);
          IF image_description_p^.page_desc [valid_count].file_offset > largest_rcv_mfw_file_offset THEN
            mmp$assign_mass_storage (new_wired_segment_number, gfv$null_sfid,
                  0, assign_backing_store_status);
            IF assign_backing_store_status.normal THEN
              largest_rcv_mfw_file_offset := image_description_p^.page_desc [valid_count].file_offset;
            ELSE
              STRINGREP (msg_string, msg_string_length, ' -- Unable Assigning Backing Store for New Wired ',
                    'Segment ', new_wired_segment_number: 4: #(16));
              syp$display_deadstart_message (msg_string (1, msg_string_length));
            IFEND;
          IFEND;
        FOREND;

      ELSE
        IF overflow THEN
          osp$system_error ('Error in recovering old mainframe wired data.', NIL);
        IFEND;
      IFEND;
    UNTIL overflow = FALSE;

    dsp$build_sequence_p (recovery_mainframe_wired_p, (pages * v$old_registers.page_size),
          v$rcv_mainframe_wired_segment_p);

    IF dmv$display_recovery_messages THEN
      pmp$get_legible_date_time (osc$mdy_date, date, osc$hms_time, time, local_status);
      STRINGREP (msg_string, msg_string_length, '  Total Wired Pages Recovered: ', pages: 7, '   ', time.hms);
      syp$display_deadstart_message (msg_string (1, msg_string_length));
    IFEND;

  PROCEND dsp$recover_mf_wired;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$resume_system', EJECT ??

  PROCEDURE [XDCL, #GATE] dsp$resume_system;

    VAR
      image_state: dst$ssr_entry,
      name_stored: ost$name;

    name_stored := dsc$will_commit;
    dsp$store_data_in_rdf (dsc$rdf_recovery_image_status, dsc$rdf_recovery, #SEQ (name_stored));

    name_stored := dsc$ready_to_run;
    dsp$store_data_in_ssr (dsc$ssr_image_status, #SEQ (name_stored));

    name_stored := dsc$nve_resumed;
    dsp$store_data_in_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, #SEQ (name_stored));

    dsp$advance_deadstart_sequence (dsc$dss_system_resumed);

    { Set the flag to request that an image file be written for recovery purposes.

    image_state.whole_slot := 0;
    dsp$store_entry_in_ssr (dsc$ssr_image_state, dsc$ssr_whole_slot, image_state);

  PROCEND dsp$resume_system;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$setup_deadstart', EJECT ??

{ PURPOSE:
{   This procedure is used during system initialization to setup the deadstart environment.
{   It is used to determine the deadstart phase from the image file.  The image file is opened
{   for segment access.

  PROCEDURE [XDCL, #GATE] dsp$setup_deadstart;

    VAR
      bad_system_core_id: boolean,
      commit_new_df: integer,
      deadstart_type: dst$ssr_entry,
      image_size: integer,
      idle_status: ost$name,
      idle_status_seq_p: ^SEQ ( * ),
      job_recovery_status: string (8),
      job_recovery_status_seq_p: ^SEQ ( * ),
      previous_recovery_status: string (8),
      previous_recovery_status_seq_p: ^SEQ ( * ),
      previous_recovery_type: string (8),
      previous_recovery_type_seq_p: ^SEQ ( * ),
      recovery_needed: boolean,
      register_values: t$hardware_registers,
      register_values_seq_p: ^SEQ ( * ),
      system_core_id: ost$name,
      status: ost$status;

    dsp$open_image_file (v$image_file_sfid, v$image_file_segment, v$image_file_p);
    dsv$actual_deadstart_phase := osv$deadstart_phase;


    { Set the file limit of the image file.  The file limit must be correct since it is used by Memory
    { Manager to mark the boundary between pages that are on the image file and pages that are still
    { in real memory.  Since the value of file limit is lost when the image file is detached, it must
    { be reset each deadstart before calling mmp$define_image_file.


    dsp$get_integer_from_rdf (dsc$rdf_image_size, dsc$rdf_production, image_size);
    dmp$set_file_limit (v$image_file_sfid, dsv$rdf_size + image_size, status);
    IF NOT status.normal THEN
      osp$system_error ('Error occurred setting file limit on image file.', ^status);
    IFEND;

    { Ensure that the SSR reflects the image file values for subsequent continuation deadstarts.

    dsp$update_image_values_in_ssr;

    IF (osv$deadstart_phase = osc$installation_deadstart) THEN
      deadstart_type.left_slot := $INTEGER (dsc$recovery_deadstart);
      deadstart_type.right_slot := $INTEGER (dsc$continuation_deadstart);
      dsp$store_entry_in_ssr (dsc$ssr_deadstart_type, dsc$ssr_whole_slot, deadstart_type);
      RETURN;
    IFEND;

    { Check and display the recovery state.

    check_recovery_state (recovery_needed, system_core_id, bad_system_core_id);

    IF recovery_needed THEN
      dsv$actual_deadstart_phase := osc$recovery_deadstart;
      IF v$image_good THEN
        syp$display_deadstart_message ('Attempting a recovery from memory image ...');
      ELSE
        IF bad_system_core_id THEN
          syp$display_deadstart_message ('Image is from a different level system and will be ignored ...');
        IFEND;
        syp$display_deadstart_message ('Attempting a recovery without image ...');
      IFEND;
    ELSE
      syp$display_deadstart_message ('System is in a recovered state ...');
    IFEND;

    { Record the current recovery type in the RDF. If a recovery without image has been attempted
    { since the last successful PF recovery, put dsc$recovery_without_image in the RDF.

    IF recovery_needed THEN
      IF v$image_good THEN
        previous_recovery_type_seq_p := #SEQ (previous_recovery_type);
        dsp$get_data_from_rdf (dsc$rdf_previous_recovery_type, dsc$rdf_production,
              previous_recovery_type_seq_p);
        IF previous_recovery_type = dsc$recovery_without_image THEN
          dsp$store_data_in_rdf (dsc$rdf_previous_recovery_type, dsc$rdf_production,
                #SEQ (previous_recovery_type));
        ELSE
          previous_recovery_type := dsc$recovery_with_image;
          dsp$store_data_in_rdf (dsc$rdf_previous_recovery_type, dsc$rdf_production,
                #SEQ (previous_recovery_type));
        IFEND;
      ELSE
        previous_recovery_type := dsc$recovery_without_image;
        dsp$store_data_in_rdf (dsc$rdf_previous_recovery_type, dsc$rdf_production,
              #SEQ (previous_recovery_type));
      IFEND;
    IFEND;

    dsp$get_entry_from_ssr (dsc$ssr_deadstart_type, deadstart_type);
    IF recovery_needed AND v$image_good THEN
      osv$deadstart_phase := osc$recovery_deadstart;
      IF (deadstart_type.right_slot <> $INTEGER (dsc$recovery_deadstart)) THEN
        deadstart_type.right_slot := $INTEGER (dsc$continuation_deadstart);
      IFEND;
      deadstart_type.left_slot := $INTEGER (dsc$recovery_deadstart);
    ELSE
      osv$deadstart_phase := osc$normal_deadstart;
      deadstart_type.right_slot := $INTEGER (dsc$continuation_deadstart);
      deadstart_type.left_slot := $INTEGER (dsc$continuation_deadstart);
    IFEND;
    dsp$store_entry_in_ssr (dsc$ssr_deadstart_type, dsc$ssr_whole_slot, deadstart_type);

    dsp$get_integer_from_rdf(dsc$rdf_commit_new_dsfile_flag,dsc$rdf_production,commit_new_df);
    IF commit_new_df = $INTEGER(TRUE) THEN
      syp$display_deadstart_message ('New system will be committed at successful ');
      syp$display_deadstart_message ('   completion of a terminate_system.');
    IFEND;

    { Initialize job recovery.

    syv$job_recovery_option := syv$setsa_job_recovery_option;
    IF syv$job_recovery_option <> syc$jre_enabled THEN
      job_recovery_status := 'disable';
    ELSE
      job_recovery_status := 'enable';
    IFEND;

    register_values_seq_p := #SEQ (register_values);
    dsp$get_data_from_rdf (dsc$rdf_register_values, dsc$rdf_production, register_values_seq_p);

    idle_status_seq_p := #SEQ (idle_status);
    dsp$get_data_from_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, idle_status_seq_p);

    previous_recovery_status_seq_p := #SEQ (previous_recovery_status);
    dsp$get_data_from_rdf (dsc$rdf_job_recovery, dsc$rdf_production, previous_recovery_status_seq_p);

    IF (previous_recovery_status = 'disable') AND (syv$recovery_override = 0) THEN

      { Previous disable - turn off job recovery to allow device management to free disk space early.

      job_recovery_status := 'disable';
      syv$job_recovery_option := syc$jre_prior_ds_disabled;
      syp$display_deadstart_message ('Job recovery disabled by prior deadstart ...');

    ELSEIF NOT v$image_good AND (idle_status <> dsc$nve_idled) THEN

      { No image - turn off job recovery to allow device management to free disk space early.

      job_recovery_status := 'disable';
      syv$job_recovery_option := syc$jre_no_image;
      syp$display_deadstart_message ('Job recovery disabled because memory image is not available ...');

    ELSEIF (system_core_id <> jmv$system_core_id) AND (syv$recovery_override = 0) THEN

      { Different system - turn off job recovery to allow device management to free disk space early.

      job_recovery_status := 'disable';
      syv$job_recovery_option := syc$jre_different_system;
      syp$display_deadstart_message
            ('Job recovery disabled because a different system is being deadstarted ...');

    ELSEIF (register_values.page_size <> osv$page_size) THEN

      { Page size is different - turn off job recovery to allow device management to free disk space early.

      job_recovery_status := 'disable';
      syv$job_recovery_option := syc$jre_page_size_mismatch;
      syp$display_deadstart_message
            ('Job recovery disabled because a different page size is being used ...');
    ELSEIF (job_recovery_status = 'disable') THEN

      { Job recovery disabled by set_system_attribute command.

      syv$job_recovery_option := syc$jre_command_disabled;
      syp$display_deadstart_message ('Job recovery disabled by set_system_attribute command ...');

    ELSE

      { Job_recovery_status = 'enable'.

      syp$display_deadstart_message ('Job recovery enabled ...');
    IFEND;

    { Disable job recovery until the next system commit.

    IF job_recovery_status = 'disable' THEN
      dsp$store_data_in_rdf (dsc$rdf_job_recovery, dsc$rdf_production, #SEQ (job_recovery_status));
    IFEND;

    { Pass image file values to memory manager for use during page fault processing on the image file.
    { Page faults beyond file limit on the image file are special cased by memory manager.  They are
    { considered to be references to that portion of real memory that has been left undisturbed since
    { the crash.  The value passed to memory manager below is the address on the image file that
    { corresponds to the first byte of NOS/VE real memory.

    mmp$define_image_file (v$image_file_sfid, dsv$rdf_size);

    dsp$advance_deadstart_sequence (dsc$dss_image_retrieved);

  PROCEND dsp$setup_deadstart;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$store_list_block', EJECT ??

{ PURPOSE:
{   This procedure stores a list block in the SSR.

  PROCEDURE [XDCL, #GATE] dsp$store_list_block
    (    list_type: dst$list_block_kind;
         list_p: ^SEQ (*));

    VAR
      list_array_index: dst$list_block_kind,
      list_array_p: [STATIC] ^dst$list_for_block := NIL,
      list_data_seq_p: ^SEQ (*),
      list_seq_p: [STATIC] ^SEQ (*) := NIL;

    IF list_array_p = NIL THEN
      ALLOCATE list_seq_p: [[REP #SIZE (dst$list_for_block) OF cell]] IN osv$mainframe_wired_heap^;
      RESET list_seq_p;
      v$list_block.list_block_p := list_seq_p;
      NEXT list_array_p IN list_seq_p;
      FOR list_array_index := LOWERBOUND (list_array_p^) TO UPPERBOUND (list_array_p^) DO
        list_array_p^ [list_array_index] := NIL;
      FOREND;
    IFEND;

    IF list_array_p^ [list_type] <> NIL THEN
      osp$system_error ('Requested list block already exists.', NIL);
    IFEND;
    ALLOCATE list_data_seq_p: [[REP #SIZE (list_p^) OF cell]] IN osv$mainframe_wired_heap^;
    list_data_seq_p^ := list_p^;
    list_array_p^ [list_type] := list_data_seq_p;

  PROCEND dsp$store_list_block;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$system_committed', EJECT ??
  FUNCTION [XDCL, #GATE] dsp$system_committed: boolean;

    dsp$system_committed := (v$current_deadstart_step >= dsc$dss_system_committed);

  FUNCEND dsp$system_committed;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$update_image_values_in_ssr', EJECT ??

{ PURPOSE:
{   This procedure saves the offset in the image file to the beginning of the image and
{   the image length in the SSR for subsequent continuation deadstarts.
{
{ NOTE:
{   The recovery device file must be open for segment access when this procedure is called.

  PROCEDURE [XDCL] dsp$update_image_values_in_ssr;

    VAR
      image_size: integer,
      rdf_size: integer,
      ssr_entry: dst$ssr_entry;

    { Store the values saved in the RDF area.  The values in the RDF area reflect the current state of the
    { image file.  It is possible to be running a system that wants to build a larger image file but not able
    { to do it.

    dsp$get_integer_from_rdf (dsc$rdf_image_table_size, dsc$rdf_production, rdf_size);
    ssr_entry.whole_slot := rdf_size;
    dsp$store_entry_in_ssr (dsc$ssr_image_offset, dsc$ssr_whole_slot, ssr_entry);

    dsp$get_integer_from_rdf (dsc$rdf_image_size, dsc$rdf_production, image_size);
    ssr_entry.whole_slot := image_size;
    dsp$store_entry_in_ssr (dsc$ssr_image_length, dsc$ssr_whole_slot, ssr_entry);

  PROCEND dsp$update_image_values_in_ssr;
MODEND dsm$recovery_services;
