?? RIGHT := 110 ??
MODULE dsm$deadstart_nos_ve ALIAS 'DSMDNV';

*copy pxiotyp
?? PUSH (LISTEXT := ON) ??
*copy pxziobs
*copy lgzclos
*copy lgzget
*copy lgzopen
*copy lgzgetp
*copy fzmark
*copy fzwords
*copyc zuttpfd
*copyc zn7ppfm
?? POP ??
*copy dsc$constant_definitions
*copy dsd$os_global_variables
*copy dsp$dst_global_variables
*copy dsp$copy_memory
*copy dsi$virtual_memory_access
*copyc dsi$support_eicb_version_4
*copyc dst$dual_state_control_block_cc
?? SKIP := 3 ??

  PROCEDURE clear_memory (address: integer;
        length: integer);

    VAR
      i: integer,
      size: integer,
      clear_request: memory_copy_header,
      buffer: array [1 .. 1000] of integer;

    size := length DIV 8;
    clear_request.pva_type := start_of_ve;
    clear_request.copy_method := nos60_to_ve60;
    clear_request.byte_rma := address;
    clear_request.length := 1000;

    FOR i := 1 TO 1000 DO
      buffer [i] := 0;
    FOREND;

    REPEAT
      IF size < 1000 THEN
        clear_request.length := size;
      IFEND;
      copy_memory (clear_request, ^buffer);
      size := size - clear_request.length;
      clear_request.byte_rma := clear_request.byte_rma + clear_request.length *
            8;
    UNTIL size = 0;
  PROCEND clear_memory;
*copy dsi$display_dayfile_message
*copy dsc$job_control_registers
*copy dsp$callsda
*copy dsp$callver
*copy dsi$deadstart_utilities
*copy dsi$k_display_control
*copy dsi$deadstart_command_processor
*copy dsi$c170_access_to_ssr
*copy dsi$transmit_data_via_ssr
?? NEWTITLE := '~~~~~   ssr service routines', EJECT ??

  PROCEDURE store_ssr_slot (name: string (4);
        slot: integer);

    VAR
      entry: integer;

    find_ssr_entry (name, entry);
    store_ssr_data (entry + 4, ^slot, 1);
  PROCEND store_ssr_slot;
?? SKIP := 3 ??

  PROCEDURE build_r_addr (VAR address: integer;
        p: dst$r_pointer);

    address := p.offset + p.rlower * 100(8) + p.rupper * 1000000(8);
  PROCEND build_r_addr;
?? OLDTITLE ??
?? NEWTITLE := '~~~~~   define central memory configuration', EJECT ??
{**********************************************************}

  VAR
    memory_available: integer,
    memory_assigned: integer,
    ssr_length: [STATIC] integer := 0,
    ssr_address: [STATIC] integer := 0,
    actual_page_size: integer,
    page_table_length: integer,
    actual_load_address: integer;

?? SKIP := 3 ??
{**********************************************************}

  PROCEDURE check_environment;

    VAR
      i: integer;

    IF NOT got_eicb_d7ty THEN
      get_dscb(dscb_d7ty,^d7ty, 1);
      { the eicb entry d7ty.eicb_version will be used to choose VER functions
      got_eicb_d7ty:= TRUE;
    IFEND;

{}
{ check for any PP's assigned to NOS/ve
{}
    FOR i := 1 TO 20 DO
      IF i < 11 THEN
        ver_request.pps [i].primary := i - 1;
      ELSE
        ver_request.pps [i].primary := i + 5;
      IFEND;
      ver_request.pps [i].kind := 0;
      ver_request.pps [i].fill := 0;
      ver_request.pps [i].status := 0;
    FOREND;
    ver_request.return_all := FALSE;
    ver_request.length := 20;
    ver_request.general_status := 0;
    IF d7ty.eicb_version < dsc$eicb_version_4 THEN
      { try old code on ver request
      callver (ver_request, stpp, TRUE);
    ELSE
      { try new ( ie. NOS 2.5.1 ) request code
      callver (ver_request, stpt, TRUE);
    IFEND;
    FOR i := 1 TO 20 DO
      IF ver_request.pps [i].status <= 1 THEN
        error_processor (pp_illegally_assigned_to_nve, fatal_error);
      IFEND;
    FOREND;
{}
{ validate cm requirements
{}
    ver_request.general_status := 0;
    ver_request.length := 2;
    callver (ver_request, stmr, TRUE);
    memory_available := ver_request.resources.available_words_div_1000 *
          bytes_per_octal_1k_words;
    ver_request.general_status := 0;
    callver (ver_request, stcm, TRUE);
    load_offset_bytes := ver_request.cm_block.fwa_div_1000 *
          bytes_per_octal_1k_words;
    memory_assigned := ver_request.cm_block.words_div_1000 *
          bytes_per_octal_1k_words;
    IF nve_memory = 0 THEN
      nve_memory := memory_available + memory_assigned;
    IFEND;
    IF (nve_memory < min_nve_memory) THEN
      error_processor (chosen_memory_less_then_nve_min, fatal_error);
    IFEND;
    dyfstrnum ('memory request', nve_memory, user_dayf);
  PROCEND check_environment;
?? EJECT ??
{**********************************************************}

  PROCEDURE set_nve_load_address;

{ Request whatever memory is needed to run ve.

    IF nve_memory > memory_assigned THEN
      ver_request.general_status := 0;
      ver_request.length := 2;
      ver_request.cm_block.words_div_1000 := (nve_memory - memory_assigned) DIV
            bytes_per_octal_1k_words;
      callver (ver_request, rscm, TRUE);
      IF (ver_request.general_status > 1) THEN
        error_processor (unable_to_obtain_request_memory, fatal_error);
      IFEND;
      load_offset_bytes := ver_request.cm_block.fwa_div_1000 *
            bytes_per_octal_1k_words;
      nve_memory := ver_request.cm_block.words_div_1000 *
            bytes_per_octal_1k_words;
    IFEND;

{ Form word address for memory limit.
    memory_limit := (load_offset_bytes + nve_memory) DIV 8;
    dyfstrnum ('load offset', load_offset_bytes, user_dayf);
    dyfstrnum ('memory size', memory_limit * 8, user_dayf);

  PROCEND set_nve_load_address;
?? OLDTITLE ??
?? EJECT ??

  PROCEDURE deadstart_nve;

    VAR
      cm_copy_info: [STATIC] memory_copy_header := [0, nos32_to_ve64,
        interface_block, 0],
      ii: integer,
      left: integer,
      right: integer,
      veparam: packed record
        fill1: 0 .. 0fffffff(16),
        stack_rma: 0 .. 0ffffffff(16),
        fill2: 0 .. 0fffffff(16),
        jps_rma: 0 .. 0ffffffff(16),
      recend;

{ provide a save area for the NOS stack

    dyfstring ('deadstartve.', debug_log);
    veparam.jps_rma := 0;
    find_ssr_entry (dsc$ssr_driver_code_buffer, ii);
    get_ssr_directory_entry (ii, left, right);
    veparam.stack_rma := (ssr_address_words + right) * 8;
    cm_copy_info.byte_rma := (dscb_d8ds + 2) * 8;
    cm_copy_info.length := 2;
    copy_memory (cm_copy_info, ^veparam);

{}
{stop C170 environment and start NOS/VE deadstart}
{initialization}
{}
    deadstart_cpu (start_dual_state);
{}
  PROCEND deadstart_nve;
?? NEWTITLE := '~~~~~   respond to nve requests', EJECT ??
*copyc dsp$claim_nve_resources

  PROCEDURE respond_to_nve_requests;

    VAR
      block: ^SEQ ( * ),
      rma: integer,
      nve_request_p: ^dst$170_request_block;

    REPEAT
      dsp$receive_data_via_ssr (block);
      IF block <> NIL THEN
        dyfstring ('Process ve request.', debug_log);
        NEXT nve_request_p IN block;
        CASE nve_request_p^.request OF

        = dsc$170_rb_request_resources, dsc$170_rb_update_free_clock =
          dsp$claim_nve_resources (nve_request_p^);

        = dsc$170_rb_call_dft_through_sda =
          rma := nve_request_p^.dft_request_rma DIV 8;
          pp_table.ssr_buffer.offset := rma MOD 100(8);
          pp_table.ssr_buffer.rlower := (rma DIV 100(8)) MOD 10000(8);
          pp_table.ssr_buffer.rupper := rma DIV 1000000(8);
          callsda (call_dft, pp_table);

        = dsc$170_rb_complete_deadstart =
          dyfstring ('complete deadstart', user_dayf);
          IF NOT nve_request_p^.terminating THEN
            jcr.r2 := xecute_runve;
            jcrset;
          IFEND;
          RETURN;

        ELSE
          error_processor (incorrect_nve_request, fatal_error);
        CASEND;
        dsp$send_data_via_ssr (block, #SIZE (block^));
        FREE block;
      ELSE
        wakeup;
        wakeup;
      IFEND;
    UNTIL FALSE;
  PROCEND respond_to_nve_requests;
?? OLDTITLE ??
?? EJECT ??

  PROCEDURE establish_ds_environment;

    check_environment;
    normalize_environment;
    set_nve_load_address;
  PROCEND establish_ds_environment;
?? SKIP := 3 ??

  PROCEDURE load_pp_boot (pp: integer);
    find_ssr;
    dyfstrnum ('load vpb.', pp, debug_log);
    dyfstring ('sci loading vcb.', user_dayf);
    pp_table.pp_number := pp;
    callsda (load_vpb, pp_table);
    dyfstring ('vcb loaded.', user_dayf);
  PROCEND load_pp_boot;
?? SKIP := 3 ??

{ PURPOSE:
{   Return a PP to C170 through the VER interface.

  PROCEDURE return_pp (pp: integer);

    IF NOT got_eicb_d7ty THEN
      get_dscb(dscb_d7ty,^d7ty, 1);
      { the eicb entry d7ty.eicb_version will be used to choose VER functions
      got_eicb_d7ty:= TRUE;
    IFEND;

    ver_request.return_all := FALSE;
    ver_request.general_status := 0;
    ver_request.length := 1;
    ver_request.pp.primary := pp;

    IF d7ty.eicb_version < dsc$eicb_version_4 THEN
      { use pre NOS 2.5.1 request code
      ver_request.pp.kind := 0;
      callver (ver_request, rtpp, TRUE);
    ELSE
      { use NOS 2.5.1 request code
      ver_request.pp.kind := non_driver_pp;
      callver (ver_request, rnpt, TRUE);
    IFEND;
  PROCEND return_pp;
?? SKIP := 3 ??

  PROCEDURE assign_pps;

    CONST
      boot_not_loaded = 2,
      deadstart_ok = 1;

    VAR
      pp: integer,
      d8st: dst$dscb_cc_d8st_word;

    PROCEDURE [XREF] obtain_pp (VAR pp: integer);

    dyfstring ('assign pps.', debug_log);

{  Obtain a PP in which to load *SCI*.  If *SDA* determines that *SCI* is
{  already executing in a PP, then the PP obtained here will be returned.

    obtain_pp (pp);
    load_pp_boot (pp);
    get_dscb (dscb_d8st, ^d8st, 1);
    WHILE d8st.sci_deadstart_status = 0 DO
      wakeup;
      get_dscb (dscb_d8st, ^d8st, 1);
    WHILEND;
    IF NOT d8st.nosve_owns_sci_pp THEN
      return_pp (pp);
    ELSE
      d8st.sci_pp_number := pp;
    IFEND;
    IF d8st.sci_deadstart_status = deadstart_ok THEN
      put_dscb (dscb_d8st, ^d8st, 1);
    ELSEIF d8st.sci_deadstart_status = boot_not_loaded THEN
      error_processor (nosve_boot_progs_not_installed, fatal_error);
    IFEND;
  PROCEND assign_pps;
?? SKIP := 3 ??

  PROCEDURE find_ssr;

    VAR
      i: integer,
      ssr_ptr: dst$r_pointer;

    dyfstring ('find ssr.', debug_log);
    get_dscb (dscb_ssrptr, ^ssr_ptr, 1);
    build_r_addr (ssr_address_words, ssr_ptr);

{ define EI rma.}
    IF ssr_address_words > 0 THEN
      dyfstrnum ('ssr address', ssr_address_words, user_dayf);
      set_ei_pva (start_of_ssr, ssr_address_words);
    IFEND;
  PROCEND find_ssr;
?? SKIP := 3 ??

{ PURPOSE:
{   This procedure updates the SSR when deadstart is initiated.

  PROCEDURE update_ssr;

    VAR
      left: integer,
      right: integer,
      ssr_entry_offset: integer,
      transfer_buffer_offset: integer,
      minilink_transfer_entry: transfer_entry;

    find_ssr;
    dyfstring ('update ssr.', debug_log);

    { Save the operator intervention flag in the SSR.

    find_ssr_entry (dsc$ssr_operator_intervention, ssr_entry_offset);
    set_ssr_directory_entry (ssr_entry_offset, 0, $INTEGER (dsv$ssr_operator_intervention));

 {  Initialize C70B and C80B for minilink communications in the event
 {  system terminated while minilink was in use.

    find_ssr_entry (dsc$ssr_c170_transfer_buffer, ssr_entry_offset);
    get_ssr_directory_entry (ssr_entry_offset, left, right);
    transfer_buffer_offset := right * 8;
    minilink_transfer_entry.offset := 0;
    minilink_transfer_entry.length := 0;
    store_ssr_data (transfer_buffer_offset, ^minilink_transfer_entry, 2);

    find_ssr_entry (dsc$ssr_c180_transfer_buffer, ssr_entry_offset);
    get_ssr_directory_entry (ssr_entry_offset, left, right);
    transfer_buffer_offset := right * 8;
    store_ssr_data (transfer_buffer_offset, ^minilink_transfer_entry, 2);

  PROCEND update_ssr;
?? NEWTITLE := '~~~~~   Normalize the EICB', EJECT ??
{*********************************************************}
{}
{normalize environment for level zero deadstart}
{}

  PROCEDURE normalize_environment;

    TYPE
      mtt$dscb_os_status_flags = packed record
        operational_mode: boolean,
        maintenance_mode: boolean,
        step_mode: boolean,
        bit56_bit52: 0 .. 37(8),
        checkpoint_complete: boolean,
        checkpoint_in_progress: boolean,
        bit49_bit48: 0 .. 3,
      recend;

    VAR
      d7st: packed record
        status_flags: mtt$dscb_os_status_flags,
        ep_status: 0 .. 03777(8),
        drop_ve_flag: boolean,
        rfu: 0 .. 777777777777(8),
      recend;

{}
{delete dropve bit and rewrite c7st word.}
{}
    get_dscb (dscb_d7st, ^d7st, 1);
    d7st.drop_ve_flag := FALSE;
    put_dscb (dscb_d7st, ^d7st, 1);
{}
  PROCEND normalize_environment;
?? OLDTITLE ??
?? EJECT ??

  PROCEDURE initialize_dstve;

    TYPE
      vebtype = PACKED RECORD
        value : 0 .. 7777(8),
        fill : 0 .. 7777777777777777(8),
      RECEND;

    VAR
      logical_cm_gt_256_mb: boolean,
      memory_size: integer,
      ve_status: integer,
      veb : vebtype;

{}
{Ensure VE is enabled in CMRDECK.
{}
    pp_table.size := #SIZE(veb);
    pp_table.data_buffer := ^veb;
    callsda (fetch_ve_enabled_status, pp_table);
    IF veb.value = 0 THEN
      error_processor (ve_not_enabled_in_cmrdeck, fatal_error)
    IFEND;
{}
{read command file}
{}
    mycmnds := 'cmdfile';
    lg#open (command_file, mycmnds, old#, input#, first#);
    f#mark (command_file, file_mark_position);
    IF ((file_mark_position = eoi#) OR (file_mark_position = eof#)) THEN
      active_cmnds_file := FALSE;
    ELSE
      active_cmnds_file := TRUE;
    IFEND;
    line_position := 4;
    beginning_line_position := line_position;

    jcrget;
    jcr.error_flag := 0;
    jcr.global_error_flag := 0;
    jcr.r2 := xecute_trmve;
    jcrset;

    ver_request.general_status := 0;
    ver_request.length := 2;
    ver_request.cm_block.words_div_1000 := 0;
    ver_request.cm_block.lwa_div_1000 := 0;
    callver (ver_request, stcm, TRUE);
    IF ver_request.general_status = 1 THEN
      memory_size := ver_request.cm_block.lwa_div_1000 *
           bytes_per_octal_1k_words;
      logical_cm_gt_256_mb := ((memory_size DIV 100000(16)) > 256);
    ELSE
      logical_cm_gt_256_mb := FALSE;
    IFEND;

    read_deadstart_command_file(logical_cm_gt_256_mb);

{}
{check for nosve already running and stop deadstart when true}
{}
    get_ve_status (ve_status);
    IF exitcd <> 0 THEN
      error_processor (attempted_to_ds_a_running_nosve, fatal_error);
    IFEND;

  PROCEND initialize_dstve;
?? NEWTITLE := '~~~~~   MAIN DSTVE PROGRAM', EJECT ??
{}
{BEGIN MAIN DSTVE PROGRAM}
{}

  PROGRAM [XDCL] dspdst;

{}
{initialize dstve
{}
    makscpb; { make me a busy system controlpoint }
    convert_title ('  DEADSTART VE  ');
    initialize_dstve;
{}
{Start NVE deadstart}
{}

    establish_ds_environment;
    assign_pps;
    update_ssr;
    deadstart_nve;
    respond_to_nve_requests;

    endprgr;
{}
  PROCEND dspdst;
MODEND dsm$deadstart_nos_ve;
