?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE OS : Define CPU' ??
MODULE osm$define_cpu;

{ PURPOSE:
{   This module defines tables and memory needed for multiple processors.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmt$request_block
*copyc dst$cpu_attributes
*copyc osc$monitor_stack_mult
*copyc osc$processor_defined_registers
*copyc osd$virtual_address
?? POP ??
*copyc i#call_monitor
?? EJECT ??
*copyc mtv$cst0
*copyc mtv$monitor_exchange_package
*copyc osv$monitor_stack_length
*copyc osv$page_size
?? OLDTITLE ??
?? NEWTITLE := 'osp$define_cpu', EJECT ??

  PROCEDURE [XDCL] osp$define_cpu
    (    cpu_attributes: dst$cpu_attributes);

    VAR
      first_cpu_started_id: ost$logical_processor_id,
      index: integer,
      mem_port_mask: ost$cpu_memory_port_mask,
      pva_offset: ost$segment_offset,
      rb: cmt$request_block,
      second_cpu_started_id: ost$logical_processor_id,
      xp_p: ^ost$exchange_package;

    { Send a request to monitor to assign the pages to monitor to contain the monitor exchange package and
    { the stack for the second CPU to be started.  Loop until enough memory has been retrieved, each call
    { to monitor retrieves one page.  The RMA value returned from the monitor call is only set on the first
    { call to monitor.  Once the RMA value is non-zero it is not changed.

    rb.request_code := syc$rc_config_mgmt_request;
    rb.kind := cmc$rbk_request_stack_memory;
    rb.rma := 0;
    pva_offset := osc$monitor_stack_mult;
    xp_p := ^mtv$monitor_exchange_package;

   /assign_loop/
    WHILE TRUE DO
      rb.status.normal := TRUE;
      rb.first_byte_address_p := #ADDRESS (#RING (xp_p), #SEGMENT (xp_p), pva_offset);
      i#call_monitor (#LOC (rb), #SIZE (rb));
      IF NOT rb.status.normal THEN
        CYCLE /assign_loop/;
      IFEND;
      pva_offset := pva_offset + osv$page_size;
      IF osv$monitor_stack_length > (pva_offset - osc$monitor_stack_mult) THEN
        CYCLE /assign_loop/;
      IFEND;
      EXIT /assign_loop/;
    WHILEND /assign_loop/;

    { Determine the CPU ids.

    first_cpu_started_id := #READ_REGISTER (osc$pr_maintenance_id);
    IF first_cpu_started_id = 0 THEN
      second_cpu_started_id := 1;
    ELSE
      second_cpu_started_id := 0;
    IFEND;

    { Determine the memory port mask of the second CPU to be started.

    mem_port_mask := 1;
    FOR index := 1 TO cpu_attributes.cpu [second_cpu_started_id].memory_port_number DO
      mem_port_mask := mem_port_mask * 2;
    FOREND;

    { Store the information retrieved in the CPU state table of the second CPU started.

    mtv$cst0 [second_cpu_started_id].memory_port_mask := mem_port_mask;
    mtv$cst0 [second_cpu_started_id].monitor_mps := rb.rma;
    mtv$cst0 [second_cpu_started_id].next_processor_state := cpu_attributes.cpu [second_cpu_started_id].state;
    mtv$cst0 [second_cpu_started_id].previous_processor_state :=
          cpu_attributes.cpu [second_cpu_started_id].state;
    mtv$cst0 [second_cpu_started_id].element_id := cpu_attributes.cpu [second_cpu_started_id].element_id;

    mtv$cst0 [0].termination_message := ' ';
    mtv$cst0 [1].termination_message := ' ';

  PROCEND osp$define_cpu;
?? OLDTITLE ??
MODEND osm$define_cpu;
