?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE System : Deadstart Initialization' ??
MODULE sym$deadstart_initialization;

{ PURPOSE:
{   This module contains the procedures used to initialize the system at system core time.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmc$logical_unit_constants
*copyc dpt$rb_display_request
*copyc dst$image_file
*copyc dst$rb_logging_request
*copyc dst$rb_system_deadstart_status
*copyc gfc$constants
*copyc jmc$special_dispatch_priorities
*copyc mme$condition_codes
*copyc osc$processor_defined_registers
*copyc oss$mainframe_pageable
*copyc oss$job_fixed
*copyc ost$processor_id_set
*copyc ost$recover_system_set_phase
*copyc tmt$rb_initiate_task
?? POP ??
*copyc cmp$configure_system_device
*copyc cmp$create_cm_device_files
*copyc dmp$activate_volume
*copyc dmp$system_initialization
*copyc dpp$configure_system_console
*copyc dsp$add_to_pp_library
*copyc dsp$advance_deadstart_sequence
*copyc dsp$build_mainframe_information
*copyc dsp$build_recovery_segment
*copyc dsp$create_pp_library
*copyc dsp$create_system_files
*copyc dsp$get_cpu_attributes
*copyc dsp$get_entry_from_ssr
*copyc dsp$fetch_boot_data
*copyc dsp$initialize_sys_msg_buffer
*copyc dsp$make_ssr_segment
*copyc dsp$prepare_deadstart_io
*copyc dsp$retrieve_mf_element_entry
*copyc dsp$save_sys_status_build_level
*copyc dsp$setup_170_request_interlock
*copyc dsp$setup_deadstart
*copyc dsp$setup_load_ppu_interlocks
*copyc i#call_monitor
*copyc jmp$activate_sys_job_template
*copyc jmp$init_cpu_dependent_names
*copyc jmp$initialize_ajl_ijl
*copyc jmp$job_monitor_xcb
*copyc jmp$load_sys_job_template
*copyc jmp$save_system_core_template
*copyc mmp$assign_device_shared_segs
*copyc mmp$disable_transient_segments
*copyc mmp$initialize
*copyc mmp$job_multiprocessing_control
*copyc mmp$pft_initialize
*copyc mmp$write_all_segments_to_disk
*copyc osp$define_cpu
*copyc osp$get_global_cpu_model_def
*copyc osp$initialize_date_time
*copyc osp$initialize_ptl
*copyc osp$initialize_signature_lock
*copyc osp$reset_heap
*copyc osp$reset_heap_ext
*copyc osp$set_global_cpu_model_def
*copyc osp$system_error
*copyc syp$check_system_level
*copyc syp$determine_mainframe_type
*copyc syp$display_deadstart_message
*copyc syp$outward_call
*copyc syp$prepare_deadstart_display
*copyc syp$process_deadstart_commands
*copyc syp$process_deadstart_status
*copyc syp$trace_deadstart_message
?? EJECT ??
*copyc cmv$system_device_data
*copyc dmv$system_device_information
*copyc dsv$ignore_image
*copyc dsv$mainframe_type
*copyc dsv$system_deadstart_status_p
*copyc gfv$null_sfid
*copyc jmv$jcb
*copyc mmv$image_file
*copyc mmv$manage_memory_utility
*copyc mmv$page_map_offsets
*copyc mmv$tick_time
*copyc mtv$scb
*copyc mtv$sys_core_init_complete
*copyc mtv$xp_initial_value
*copyc osv$180_memory_limits
*copyc osv$cpus_logically_on
*copyc osv$cpus_physically_configured
*copyc osv$deadstart_phase
*copyc osv$job_fixed_heap
*copyc osv$mainframe_wired_cb_heap
*copyc osv$mainframe_wired_heap
*copyc osv$page_size
*copyc pmv$quantum
*copyc tmv$job_debug_ring_p
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  VAR
    osv$jf_heap_min_frag_alloc_size: [XDCL] integer := 0c(16),
    osv$jp_heap_min_frag_alloc_size: [XDCL, #GATE] integer := 0c(16),
    osv$mp_heap_min_frag_alloc_size: [XDCL] integer := 0c(16),
    osv$mw_heap_min_frag_alloc_size: [XDCL] integer := 0c(16),
    osv$ts_heap_min_frag_alloc_size: [XDCL, #GATE] integer := 0c(16),

    dsv$automatic_system_restart: [XDCL] boolean := FALSE,

    jmv$system_job_template_name: [XDCL] ost$name := 'sj',
    osv$mainframe_pageable_heap: [XDCL, #GATE, oss$mainframe_pageable] ^ost$heap,

    osv$recover_system_set_phase: [XDCL, #GATE] ost$recover_system_set_phase := osc$recovery_not_required,
    syv$image_file_adtt_ptr: [XDCL] ^cell := NIL,
    syv$job_template_cbp: [XDCL, oss$job_fixed] ost$external_code_base_pointer,
    syv$system_job_multiprocessing: [XDCL] boolean := FALSE,

    tmv$job_debug_ring: [XDCL, oss$job_fixed] ost$ring := 0,

    system_task_initialized: boolean := FALSE;

  VAR
    v$mainframe_wired_heap_limit: [XDCL, #GATE] integer := 0;

?? OLDTITLE ??
?? NEWTITLE := 'make_outward_call', EJECT ??

{ PURPOSE:
{   This procedure makes an outward call to the correct execution control block.

  PROCEDURE make_outward_call
    (VAR xcb_p: ^ost$execution_control_block);

    VAR
      pva: ost$pva,
      stack_pp: ^^cell;

    pva := xcb_p^.xp.tos_registers [3].pva;
    xcb_p^.xp.tos_registers [3].pva.offset := xcb_p^.xp.tos_registers [3].pva.offset + 416;
    stack_pp := #LOC (pva);
    syp$outward_call (^syv$job_template_cbp, stack_pp^, 3);

  PROCEND make_outward_call;
?? OLDTITLE ??
?? NEWTITLE := 'retrieve_cpu_dependent_values', EJECT ??

{ PURPOSE:
{   This procedure initializes CPU dependent values.

  PROCEDURE retrieve_cpu_dependent_values;

    TYPE
      t$a0_a1_offsets = RECORD
        fill1: string (12),
        a0_offset: 0 .. 0ffffffff(16),
        fill2: string (4),
        a1_offset: 0 .. 0ffffffff(16),
      RECEND;

    VAR
      a0_a1_offsets_p: ^t$a0_a1_offsets,
      global_processor_model_def: ost$processor_model_definition;

    osp$set_global_cpu_model_def;

    osp$get_global_cpu_model_def (global_processor_model_def);
    pmv$quantum := global_processor_model_def.quantum;
    mmv$tick_time := global_processor_model_def.tick_time;

    { The default values of the variables managed by the Manage Memory Utility have already been saved in the
    { procedure mmp$initialize in mmm$deadstart_initialization.  But now mmv$tick_time has been reset.
    { Therefore reset the default in mmv$manage_memory_utility

    mmv$manage_memory_utility.ma [mmc$mmu_ma_tt].default := mmv$tick_time;

    mtv$xp_initial_value.tos_registers[1].pva.offset := mmv$page_map_offsets [mmc$pmo_r1_stack] *
          osv$page_size + mmc$ring_crossing_offset;
    mtv$xp_initial_value.tos_registers[2].pva.offset := mmv$page_map_offsets [mmc$pmo_r2_stack] *
          osv$page_size + mmc$ring_crossing_offset;
    mtv$xp_initial_value.tos_registers[3].pva.offset := mmv$page_map_offsets [mmc$pmo_r3_stack] *
          osv$page_size + mmc$ring_crossing_offset;
    a0_a1_offsets_p := #LOC (mtv$xp_initial_value);
    a0_a1_offsets_p^.a0_offset := mmv$page_map_offsets [mmc$pmo_r1_stack] * osv$page_size +
          mmc$ring_crossing_offset;
    a0_a1_offsets_p^.a1_offset := mmv$page_map_offsets [mmc$pmo_r1_stack] * osv$page_size +
          mmc$ring_crossing_offset;

  PROCEND retrieve_cpu_dependent_values;
?? OLDTITLE ??
?? NEWTITLE := 'osp$initialize', EJECT ??

{ PURPOSE:
{   This procedure is the starting procedure for jobs, including the system job.

  PROGRAM [XDCL] osp$initialize;

    VAR
      activate_message: string (20),
      boot_data_seq_p: ^SEQ ( * ),
      cpu_attributes: dst$cpu_attributes,
      cpu_index: 0 .. osc$max_number_of_processors,
      display_message: string (60),
      display_message_size: integer,
      display_rb: dpt$rb_display_request,
      dft_rb: dst$rb_logging_request,
      ds_rb: dst$rb_system_deadstart_status,
      image_length: dst$ssr_entry,
      limit: integer,
      name: ost$name,
      ptl_register: integer,
      rb: tmt$rb_initiate_task,
      status: ost$status,
      test_offset: integer,
      xcb_p: ^ost$execution_control_block;

    xcb_p := jmp$job_monitor_xcb ();

    IF system_task_initialized THEN
      make_outward_call (xcb_p);
    IFEND;

    system_task_initialized := TRUE;

    { Initialize the XCB.

    xcb_p^.dispatching_priority := jmc$priority_system_job;
    xcb_p^.dispatching_priority_bias_id := jmc$dpb_absolute;
    xcb_p^.relative_task_priority := 128;
    xcb_p^.pit_count := 7fffffff(16);
    xcb_p^.iocb_p := NIL;
    xcb_p^.assign_active_sfid := gfv$null_sfid;
    xcb_p^.processor_selections := - $ost$processor_id_set [ ];
    xcb_p^.requested_processor_selections := $ost$processor_id_set [ ];
    xcb_p^.task_kind := osc$tk_nosve_task;
    jmv$jcb.jcb_identifier := 0ff00(16);
    jmv$jcb.cptime_next_age_working_set := 20000000;
    jmv$jcb.page_aging_interval         := 20000000;
    jmv$jcb.cyclic_aging_interval       := 10000000;
    jmv$jcb.next_cyclic_aging_time := #free_running_clock (0) + 60000000;
    jmv$jcb.max_working_set_size := 16000;
    jmv$jcb.min_working_set_size := 20;
    jmv$jcb.detached_job_wait_time := 0;
    jmv$jcb.signal_interval := 0ffffffff(16);
    tmv$job_debug_ring_p := #LOC (tmv$job_debug_ring);

    { Set image file active so that memory manager will use deadstart upper limit as upper bound of
    { available memory when assigning pages on page faults.

    mmv$image_file.active := TRUE;

    { Define the upperbound of memory to be used during deadstart, it will be restricted to the size of the
    { memory image.  Cannot use all of memory on a recovery deadstart until recovery is complete.

    osv$page_size := 512 * (128 - #READ_REGISTER (osc$pr_page_size_mask));
    osv$180_memory_limits.lower := ((osv$180_memory_limits.lower + osv$page_size - 1) DIV osv$page_size) *
          osv$page_size;

    IF osv$180_memory_limits.upper > (osv$180_memory_limits.lower + dsc$image_size) THEN
      osv$180_memory_limits.deadstart_upper := osv$180_memory_limits.lower + dsc$image_size;
    ELSE
      osv$180_memory_limits.deadstart_upper := osv$180_memory_limits.upper;
    IFEND;

    mmp$initialize;

    limit := gfc$fde_table_base - #OFFSET (osv$mainframe_wired_heap) - 50000;
    v$mainframe_wired_heap_limit := limit;
    osp$reset_heap_ext (osv$mainframe_wired_heap, limit, TRUE, 1, osv$mw_heap_min_frag_alloc_size,
          osv$mw_heap_min_frag_alloc_size, osv$mw_heap_min_frag_alloc_size);
    osp$reset_heap (osv$mainframe_wired_cb_heap, 3fffffff(16), TRUE, 1);
    osp$reset_heap_ext (osv$mainframe_pageable_heap, 3fffffff(16), TRUE, 1, osv$mp_heap_min_frag_alloc_size,
          osv$mp_heap_min_frag_alloc_size, osv$mp_heap_min_frag_alloc_size);

    syp$determine_mainframe_type;

    { Set up the variables to the DFT block.

    dft_rb.reqcode := syc$rc_logging_request;
    dft_rb.action := dsc$rla_dft_setup_variables;
    i#call_monitor (#LOC (dft_rb), #SIZE (dft_rb));

    dsp$make_ssr_segment;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      ds_rb.reqcode := syc$rc_system_deadstart_status;
      ds_rb.action := dsc$rb_sds_retrieve_bct_flag;
      ds_rb.bct_flags := dsc$rb_sds_bct_ar_control;
      i#call_monitor (#LOC (ds_rb), #SIZE (ds_rb));
      dsv$automatic_system_restart := NOT ds_rb.bct_flag_set;
    ELSE
      dsv$automatic_system_restart := FALSE;
    IFEND;

    { Retrieve the System Deadstart Status variable from the boot memory.

    ALLOCATE dsv$system_deadstart_status_p IN osv$mainframe_wired_heap^;
    boot_data_seq_p := #SEQ (dsv$system_deadstart_status_p^);
    dsp$fetch_boot_data (dsc$boot_system_ds_status, boot_data_seq_p);

    { Set the build level in the System Deadstart Status data.

    dsp$save_sys_status_build_level;

    { Initialize the job fixed heap.

    osp$reset_heap_ext (osv$job_fixed_heap, 100000000, TRUE, 1, osv$jf_heap_min_frag_alloc_size,
          osv$jf_heap_min_frag_alloc_size, osv$jf_heap_min_frag_alloc_size);

    { This next procedure must be done very early to prepare the displays for output.  Anything done
    { before this procedure will not be able to write to the screen.

    dpp$configure_system_console;
    syp$prepare_deadstart_display;
    dsp$build_mainframe_information;

    { The following code is to verify that the JCB and XCB have not grown to
    { beyond the defined size limits. The assembly language size constraints must
    { be greater than or equal to the size of the structure. The assembly
    { language constants are defined in the module SYA$CONSTANTS.

    test_offset := #OFFSET (xcb_p);
    IF #SIZE (jmv$jcb) > test_offset THEN
      syp$process_deadstart_status ('Job Control Block Overflow.', TRUE, status);
    IFEND;

    test_offset := xcb_p^.sdt_offset;
    IF #SIZE (xcb_p^) > test_offset THEN
      syp$process_deadstart_status ('Execution Control Block Overflow.', TRUE, status);
    IFEND;

    { Initialize the signature lock variables used by the deadstart area.

    dsp$setup_load_ppu_interlocks;
    dsp$setup_170_request_interlock;

    { Initialize the buffer used to hold messages from monitor destined for the engineering log.

    dsp$initialize_sys_msg_buffer;

    syp$display_deadstart_message ('Initializing production environment ...');

    osp$initialize_date_time (status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error initializing date and time:', TRUE, status);
    IFEND;

    { Check the system level number in the SSR for compatability between VCB and system core.

    syp$check_system_level;

    dsp$advance_deadstart_sequence (dsc$dss_ssr_built);

    { Create the PP library.

    dsp$create_pp_library;

    { The call to retrieve_cpu_dependent_values must come before the call to syp$process_deadstart_commands.

    retrieve_cpu_dependent_values;

    { Prepare the deadstart device environment.  Retrieve the system device data from the boot memory.

    boot_data_seq_p := #SEQ (cmv$system_device_data);
    dsp$fetch_boot_data (dsc$system_device_data, boot_data_seq_p);

    dmv$system_device_product_id := cmv$system_device_data [cmc$sdt_disk_device].unit_id;

    cmp$configure_system_device (status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error configuring the system device:', TRUE, status);
    IFEND;

    dsp$prepare_deadstart_io (status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error preparing deadstart input:', TRUE, status);
    IFEND;

    dmv$system_device_lun := cmc$job_template_unit_ordinal;

    syp$process_deadstart_commands (status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error reading deadstart commands:', TRUE, status);
    IFEND;
    dsp$advance_deadstart_sequence (dsc$dss_dcfile_read);

    { Set the console bell status from the system attribute.

    display_rb.reqcode := syc$rc_update_system_display;
    display_rb.action := dpc$da_set_console_bell_status;
    i#call_monitor (#LOC (display_rb), #SIZE (display_rb));

    { Mmp$disable_transient_segments MUST be done AFTER syp$process_deadstart_commands.

    mmp$disable_transient_segments;

    dsp$get_cpu_attributes (cpu_attributes);
    osv$cpus_physically_configured := cpu_attributes.count;
    osv$cpus_logically_on := 0;

    mtv$scb.cpus.logically_on := $ost$processor_id_set [];
    FOR cpu_index := 0 TO cpu_attributes.count - 1 DO
      IF cpu_attributes.cpu [cpu_index].state = cmc$on THEN
        osv$cpus_logically_on := osv$cpus_logically_on + 1;
        mtv$scb.cpus.logically_on := mtv$scb.cpus.logically_on + $ost$processor_id_set [cpu_index];
      IFEND;
      xcb_p^.requested_processor_selections := xcb_p^.requested_processor_selections +
            $ost$processor_id_set [cpu_index];
    FOREND;
    xcb_p^.processor_selections := mtv$scb.cpus.logically_on;
    mtv$scb.cpus.available_for_use := mtv$scb.cpus.logically_on;

    syp$trace_deadstart_message ('initialize cpu dependent names');
    jmp$init_cpu_dependent_names (status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error initializing cpu dependent names:', TRUE, status);
    IFEND;

    syp$trace_deadstart_message ('initialize system tables');
    jmp$initialize_ajl_ijl;

    { Initialize the dispatcher tables and variables.  Allocate the PTL, make a PTL entry for the
    { preloaded system task and enter the system task into the dispatcher tables.

    osp$initialize_ptl;
    rb.xcb_p := jmp$job_monitor_xcb ();
    rb.reqcode := syc$rc_initiate_task;
    rb.wait := osc$nowait;
    i#call_monitor (#LOC (rb), #SIZE (rb));

    mmp$pft_initialize;
    syp$trace_deadstart_message ('save system core template');
    jmp$save_system_core_template (status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error saving system core template:', TRUE, status);
    IFEND;

    { Set up multiprocessing attributes.

    IF osv$cpus_physically_configured > 1 THEN
      osp$define_cpu (cpu_attributes);
    IFEND;

    { Initialize device management. Initialize volume, volume online and table initialization.
    { Does not activate the volume.

    syp$trace_deadstart_message ('device initialization');
    dmp$system_initialization (status);
    IF NOT status.normal THEN
      display_message := 'Error in device initialization:';
      display_message_size := 31;
      IF status.condition = mme$volume_unavailable THEN
        display_message (display_message_size + 1, 23) := ' mme$volume_unavailable';
        display_message_size := display_message_size + 23;
      IFEND;
      syp$process_deadstart_status (display_message (1, display_message_size), TRUE, status);
    IFEND;

    IF (osv$deadstart_phase = osc$installation_deadstart) THEN
       syp$trace_deadstart_message ('building recovery segment');
       dsp$build_recovery_segment;
    IFEND;

    { Establish recovery status from 'memory image file' on system device, also recover 'old'
    { mainframe_wired_segment.

    syp$trace_deadstart_message ('setup deadstart environment');
    dsp$setup_deadstart;

    { Paging to mass storage, device files only is allowed at this point.

    dsp$advance_deadstart_sequence (dsc$dss_install_templates);
    name := jmv$system_job_template_name;

    IF osv$deadstart_phase = osc$installation_deadstart THEN
      syp$trace_deadstart_message ('creating cm device files');
      cmp$create_cm_device_files (status);
      IF NOT status.normal THEN
        syp$process_deadstart_status ('Error in creating cm device files:', TRUE, status);
      IFEND;

      dsp$create_system_files (status);
      IF NOT status.normal THEN
        syp$process_deadstart_status ('Error in creating system files:', TRUE, status);
      IFEND;
    IFEND;

    syp$trace_deadstart_message ('add the non boot drivers to the pp library');
    dsp$add_to_pp_library;

    syp$trace_deadstart_message ('loading template files');
    jmp$load_sys_job_template (name, status);
    IF NOT status.normal THEN
       syp$process_deadstart_status ('Error in loading template files:', TRUE, status);
    IFEND;

    syp$trace_deadstart_message ('activate system device');
    dmp$activate_volume (dmv$system_device_lun, status);
    activate_message := 'ACTIVATING ';
    activate_message (12, *) := dmv$system_device_recorded_vsn;
    syp$trace_deadstart_message (activate_message);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error in activating system device:', TRUE, status);
    IFEND;

    dsp$advance_deadstart_sequence (dsc$dss_templates_installed);

    { Activate the job template.

    syp$trace_deadstart_message ('activate system job template');
    jmp$activate_sys_job_template (name, syv$job_template_cbp, status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error in activating job template:', TRUE, status);
    IFEND;

    { End of system core initialization.

    mtv$sys_core_init_complete := TRUE;

    { At this point memory manager is completely initialized with full capabilities.
    { Flush all segments to disk.

    syp$trace_deadstart_message ('writing system core to disk');
    mmp$write_all_segments_to_disk (status);
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error in writing system core:', TRUE, status);
    IFEND;
    IF syv$system_job_multiprocessing THEN
      mmp$job_multiprocessing_control (TRUE, status);
    IFEND;

    syp$trace_deadstart_message ('outward call to job template');
    dsp$advance_deadstart_sequence (dsc$dss_outward_call_to_jt);

    make_outward_call (xcb_p);

  PROCEND osp$initialize;
?? OLDTITLE ??
MODEND sym$deadstart_initialization;
