osm$prepare_os_environment  IDENT
         list      1,1,0
         title     c'OS environment interface preset and CTI interface.'
         space     4
.        TRADE SECRET - PROPRIETARY NOTICE.
.        COPYRIGHT CONTROL DATA SYSTEMS INC. 1992
.        The material contained herein is the property of Control Data
.        Systems Inc and is intended soley for use in the  performance
.        of  contracted  Maintenance  under a Control Data maintenance
.        services agreement.  This material is proprietary to  Control
.        Data  Systems Inc  and  is  not to be disclosed other than to
.        employees  of  Control  Data  Systems Inc  or  other  persons
.        specifically authorized to have access to  this  material  in
.        accordance  with  the  terms and conditions of a Control Data
.        maintenance services agreement.
         page
...
.        CEI       - A170 Environment Interface.
.
.        A. E. Murray  11-1-77
.        B. R. Hanson   -1-80
.        G. I. Matkovitz  7-1-80
.        B. R. Hanson     8-12-81
.
.        This program provides  the  necessary  interface  between  an
.        operating  system  using  the  C170  virtual  machine and the
.        native mode error processing  of  the  C180  computer.   This
.        program  also  provides an interface to C170 NOS/ve deadstart
.        programs when NOS/ve is not present.  The primary purpose  is
.        to  simulate  with software running in executive state of the
.        C180 to achieve the following  things.   1)  The  effects  of
.        errors occurring in the C170 virtual machine that differ from
.        those  of  the  C170  Hardware.  2) The deadstart of the C170
.        virtual machine.  3) The presence of  the  CMU  on  the  C170
.        hardware.  4)  The  presence of  a block move instruction for
.        storage move.  5) The  C170 OS-NOS/ve  interface  through the
.        017 instruction.
         page
*copy asmregs
*copy osa$ei_constant_definitions
*copy osa$dual_state_control_block
*copy osa$ei_stack_frame
*copy sya$xp_and_sf_constants
         PAGE
C180EI   SECTION   working,read+execute+write,,0,8
         USE       C180EI
ei_pva   bss       0                   .pva for EI
         space     4
...
.        LIT       - Load Interface Table.
.
.        The load interface table provides the information required
.        by CTI to load and initially start EI executing.
.
.        Define the load size of EI.
.
         def       osv$ei_load_size_in_bytes
osv$ei_load_size_in_bytes bss 0
EI_LBA   vfd,32    2000(16)
.
.        Define the EI version number and the version and level of
.        the dual state control block.  The format of this is rigidly
.        defined.  If it is changed the utility that packages EI for CIP
.        tapes must also be modified.
.
         def       osv$ei_version
osv$ei_version bss 0
         vfd,6     0                   .filler
         vfd,6     ost$ei              .os type = EI
         vfd,6     if_versn            .Interface version
         vfd,6     if_level            .Interface level
.
.        The version number is a decimal number that is put in hex for convenience
.        when checking version number in memory.
.
         vfd,8     030(16)             .EI version number
.
.        DEFINE STOP C170 ADDRESS.
.
         def       osp$ei_halt
         align     0,8
osp$ei_halt bss    0
         brreq     X0,X0,osp$ei_halt    .STOP THE MUSIC
.
.        Date OSAEI deck changed.
.
         def       osv$ei_assembly_date
osv$ei_assembly_date bss 0
*put '  vfd,32 '//$substr($date(iso),6,2)//$substr($date(iso),9,2)//$substr($date(iso),1,4)//'(16)'

.        Relative byte offset of MPS and CTI request word.
.
         def       osv$ei_mps_offset
osv$ei_mps_offset bss 0
         vfd,32    tmxp
         vfd,32    cti_req
         space     10
..
.        cti_req   - CTI request block.
.
         def       osv$ei_cti_request_block
osv$ei_cti_request_block bss 0
CTI_REQ  vfd,16    0                   .function code
         vfd,16    0                   .parameter 0
         vfd,32    0                   .parameter 2
         vfd,64    0                   .parameter 3 mrt_frc
         vfd,64    0                   .parameter 4 mrt_wcc
         vfd,64    0                   .parameter 5 hdw_wcc
         vfd,64    0                   .parameter 6 returned value
million  vfd,64    1000000             .one million constant
sec_year vfd,64    31536000            .seconds in a non leap year
sec_day  vfd,64    86400               .seconds in a day
delta    vfd,64    1209600000000       .two week delta
dual_cpu equ       2                   .defines if C170 state can use both CPUs
cpus     equ       3
rbl      equ       50                  .response buffer length.
         PAGE
..
.        PRS       - Environment Interface Preset.
.
.        EI is entered here under two conditions, to initially preset
.        the environment and to do some utility functions for CTI after
.        a system failure without reloading EI.  When EI is restarted
.        none of the initialization is required because its environment
.        has already been initialized.
.
.        The initial environment when starting from scratch that is
.        provided by CTI includes only two page table entries - one for the
.        first page of the page table, and one for the first page of EI.
.        All the preset code must fit within 512 bytes to be able to work
.        with any page size.  EI is entered with traps disabled; traps are
.        enabled when initialized to the point where it can take traps.
.        CTI sets up the PTA, PSM, PTL and MPS registers
.        and changes the segment table address within the preset monitor
.        exchange package (MXP).  EI must build the page table by adding
.        page table entries for the page table, EI's code segment, EI's
.        stack segment, and the OS segment.   EI also creates a monitor and
.        job exchange package for each processor and defines their respective
.        monitor and job stack frame save area.
.
         def       osp$prepare_os_environment
osp$prepare_os_environment equ $
prs0     ente      x3,0                .EI preset complete flag, this instruction is
                                       . modified when initialization complete, set
                                       . to a nonzero value.
prs_comp equ       prs0+2
         ente      x1,r_psm            .page size mask
         brrne     x3,x0,re_ei         .if reentering EI.
         cpysx     x2,x1
         isom      xf,x0,47
         shfx      x2,x2,x0,9
         iorx      xf,x2               .form mask for page offset and ASID from SVA
         notx      xe,xf
         incx      xe,1                .page size in bytes
         ente      x1,r_ptl            .page table length
         cpysx     x2,x1
         ente      xa,3f(16)           .form page table segment offset
         notx      xa,xa
         andx      xa,x2
         shfc      xa,xa,x0,21
         incr      x2,1
         shfx      xd,x2,x0,12         .page table length in bytes
         lbyts,2   x3,a5,x0,pt_asid
         shfx      x3,x3,x0,32         .SVA for Page Table segment
         iorx      x3,xa
         addax     a6,xa               .set conditional offset for large memory
         cpyrr     x5,xa
         tpage     x6,a6
         addpxq    a7,x0,prs1
         brreq     x0,x0,cseg          .create PT entry for page 0 with continue bit.

.        Create page table entry for real page 0 of page table but page 1 relative to the SVA.

prs1     cpyrr     xc,x3               .save SVA of page 1 of page table.
         isob      xb,x3,x0,37*64+26
         brrgt     xd,xb,prs2          .if page table is larger than 1 page.
         cpyrr     x3,xd
         iorx      x3,xa
prs2     cpyrr     x5,x3               .last byte address of first page or page table
         tpage     x6,a6               .RMA of the page table
         addpxq    a7,x0,prs3
         brreq     x0,x0,cseg          .create PT entry for page 0 of page table again

.        Now there are 2 page table entries for page 0 of the page table, one with an offset
.        of zero relative to the PVA and another one with the page size as an offset relative
.        to the PVA.  Clear page table entry with PVA offset of zero in the page table.

prs3     addax     a6,xe               .new PVA for the page table, page 0
         entp      x8,0                .invalid no continue
         cpyrr     x3,xa               .set starting SVA
         cpyrr     x5,xc               .set segment length, 1 page
         addpxq    a7,x0,prs4
         brreq     x0,x0,cseg0         .clear PT entry for page 0 of page table.

.        Define all page table entries for page table relative to offset of page size
.        for the PVA.

prs4     addr      x5,xd               .set page table lba
         tpage     x6,a6
         addpxq    a7,x0,prs5
         brreq     x0,x0,cseg          .define full page table segment
.
prs5     addax     a_static,x3         .start of static shared variables
         lbyts,2   x3,a5,x0,ei_asid
         shfx      x3,x3,x0,32         .create SVA for EI segment
         tpage     x6,a5               .RMA of EI segment
         lbyts,4   x5,a5,x0,osv$ei_load_size_in_bytes .EI segment length
         addaq     a_tos,a_static,static_size
         addpxq    a7,x0,wait_for_request  .set return address
         brreq     x0,x0,cseg          .create EI segment
         page
..
.        CSEG - Create Segment.
.                  This procedure creates the page table entries for the specified
.                  segment. It can also be entered at CSEG0 but the caller is
.                  responsible for providing the valid and continue bits for the
.                  page table entry.
.
.        Entry conditions:
.                  x3 = SVA of start of segment.
.                  x6 = RMA of start of segment.
.                  x5 = LBA of segment.
.                  x8 = page table entry valid and continue bits if entered at CSEG0.
.                  xe = page size in bytes.
.                  xf = page offset mask.
.                  a7 = return address.
.
.        Exit conditions:
.                  x3 = SVA of page following segment created.
.                  x6 = RMA of page following segment created.
.
.        uses registers.
.                  x - 1, 2, 3, 4, 6, 8.
.
cseg     entp      x8,3                .valid + continue bit
         shfx      x8,x8,x0,62-0
cseg0    lpage     x2,x3,x1
         cpyxx     x1,x3
         andx      x1,xf               .form segment/page identifier
         shfx      x4,x6,x0,-9         .form page frame address
         shfr      x1,x1,x0,1          .trim sign bit from offset
         shfx      x1,x1,x0,22-9-1
         iorx      x1,x4
         iorx      x1,x8
         sbyts,8   x1,a6,x2,0          .store page table entry
         addr      x6,xe               .update RMA
         addr      x3,xe               .update SVA
         brrgt     x5,x3,cseg0         .if more entries to build
         brdir     a7,x0               .return

pof      bss       0                   .page overflow check.
         error,pof>511  c'EI initialization overflows minimum page size.'

.        End of code that must fit in 512 bytes.  Page table entries created for
.        the page table and the EI code segment.

         PAGE
..
.                  EI preset loop.  This is where EI waits for the next request from
.                  CTI.  After request is processed control is returned to
.                  'complete_function' by each request processor.
.
.        INPUT: complete_function
.                  a5 = PVA of first byte address of EI code segment.
.                  a7 = PVA of response buffer.
.                  a9 = address of where continue function should go to complete
.                       function.
.                  x7 = byte length of response buffer.
.
.        INPUT: wait_for_request
.                  a_rac = OS segment pointer.
.                  a_static = pointer to static shared variables.
.                  x_flc = last byte offset + 1 of OS field length.
.

complete_function bss 0
         tpage     x1,a7
         sbyts,4   x1,a5,x0,cti_req+4  .save rma of response block
         shfx      x7,x7,x0,-2         .response buffer length in half words.
         sbyts,2   x7,a5,x0,cti_req+2  .save block size in half words.
         entp      x2,0
         sbyts,2   x2,a5,x0,cti_req    .clear function code

.        INPUT: wait for request.
.                  a5 = PVA of first byte address of EI code segment.

wait_for_request bss 0
         cpyax     x1,a5
         purge     x1,3
         lbyts,2   x2,a5,x0,cti_req    .check for request
         brreq     x2,x0,wait_for_request
         entp      x1,list_entries
         brrge     x2,x1,osp$ei_halt   .if invalid function
         entp      x7,0                .initialize response buffer length.
         shfx      x2,x2,x0,1
         incr      x2,1
         brrel     x2
.
.        Table of CTI request processors.
.

list     bss       0
         brreq     x0,x0,complete_function
         brreq     x0,x0,init_stack
         brreq     x0,x0,scan_cm
         brreq     x0,x0,check_cm
         brreq     x0,x0,continue
         brreq     x0,x0,fetch_frc
         brreq     x0,x0,cfv
         brreq     x0,x0,cnf
         brreq     x0,x0,cpi
list_entries equ ($-list)/4
         page
..
.        init_stack - initialize stack and OS (NOS or NOS/BE) segments.
.                  Create stack segments for EI and initialize.  Create segment
.                  for the OS.  Initialize monitor and job exchange package for
.                  each CPU.  Traps are enabled before exiting this procedure.
.                  Values are saved that are needed for reentering EI.
.
.        ENTRY:
.                  a_static = pointer to static shared variables.
.                  a5 = pointer to first byte of EI code segment.
.                  x7 = 0, response buffer length.
.
.        EXIT:
.                  a_csf = initilized to top of stack for remainder of execution.
.                  a7 = response buffer address.
.                  x7 = byte length of response buffer.
.                  x_flc = last byte offset + 1 of OS field length.
.                  (a7) = RMAs of first byte of EI stack (last byte address + 1 of
.                         host operating system) and all EI exchange packages.  The
.                         RMA of region right after the last exchange package stack
.                         is returned as the beginning of the CTI reserved area.
.

init_stack bss     0
         sa        a_static,a5,pcbp+8+2  .update code based pointers
         sa        a_static,a5,mcbp+8+2
         sa        a_static,a5,ocbp+8+2

         cpyax     x2,a_static
         lbyts,2   x3,a5,x0,sf_asid    .stack frame asid
         shfx      x3,x3,x0,32
         cpyrr     x3,x2               .SVA for stack segment
.
.        calculate size of stack segment based on number of cpus.
.
         lbyts,1   xc,a5,x0,cti_req+cpus
         mulxq     x5,xc,sf_size       .stack frame size per processor
         addrq     x5,x5,static_size+dscbl-1
         lbyts,4   xa,a5,x0,cti_req+4
         addr      x5,xa               .add cti block size
         tpage     x6,a5               .RMA of EI segment
         subx      x6,x5
         isom      x9,x0,50
         andx      x9,xf               .form mask >= 8192
         andx      x6,x9               .form multiple of 8192
         addr      x5,x3
         cpyxx     x7,x6
         addpxq    a7,x0,ini1
         brreq     x0,x0,cseg          .create stack segment
.
ini1     tpage     x5,a_static         .LBA of OS segment
         subr      x6,x7
         subr      x6,xa               .ignore CTI save area
         shfx      x7,x6,x0,-3         .length of stack segment in words
         lbyts,2   x3,a5,x0,os_asid
         shfx      x3,x3,x0,32         .SVA of OS segment
         entp      x6,0                .RMA of OS segment
         addpxq    a7,x0,ini2
         brreq     x0,x0,cseg          .create OS segment
.
ini2     entp      x0,0
         entp      x1,0
         decr      x7,1
ini3     sxi       x0,a_static,x1,0    .clear stack segment
         brinc     x7,x1,ini3

         sbyts,8   x0,a_static,x0,pva_of_first_dftb
.
         addpxq    a9,x0,osp$halt_ei   .Set pva of EI halt routine.
         sa        a9,a_static,pva_halt_ei
         addpxq    a9,x0,osp$segment_table  .Set pva of EI's segment table.
         sa        a9,a_static,pva_segment_table
         la        a9,a5,osp$afe
         sa        a9,a_static,pva_due_handler
         la        a9,a5,osp$aaj
         sa        a9,a_static,pva_abort_job
         lbyts,1   x1,a5,x0,cti_req+dual_cpu
         sbyts,1   x1,a_static,x0,dual_170
.
         sa        a_nos,a_static,pva_of_os  .Set pva of OS.
.
         cpyxx     x_flc,x5
         cpyaa     a_csf,a_tos         .Set address for first monitor xp.
         addaq     a7,a_tos,sf_wrk     .Set response buffer address.
         tpage     x5,a_static
         sbyts,4   x5,a7,x0,0
         sbyts,1   xc,a5,x0,nop        .Save number of processors.
         sa        a_csf,a5,mxp0_p     .Save address of monitor xp for cpu 0.
         entp      x7,4                .Set index for next value in response buffer.
         addpxq    a9,x0,ini4          .Set return address.
         brreq     x0,x0,ixp           .Initialize EI exchange packages and stacks.

ini4     bss       0
         cpyaa     a_dscb,a_csf        .pointer to fake dscb
         sa        a_dscb,a_static,pva_of_dscb
         addaq     a_csf,a_dscb,dscbl  .pointer to CTI reserved area
         tpage     x5,a_csf
         sbyts,4   x5,a7,x7,0          .return RMA of CTI reserved area.
         incr      x7,4

.        Update A_TOS in the running exchange package so that the monitor exchange
.        package just created will not be overwritten when traps are taken.  Use
.        the stack of first monitor xp created for this value.  Also update in
.        the initial exchange package for use when EI reentered.

         addaq     a_tos,a_tos,sf_monitor_stack
         sa        a_tos,a5,tmxp+xp_a0 .save sfsa of monitor's stack
         sa        a_tos,a5,tmxp+xp_rn1  .store top of stack
         sxi       x_flc,a5,x0,tmxp+xp_x0+(0f(16)*8)  .Save x_flc in x_flc of xp
                                       . that is used when EI is reentered.
         ente      x0,r_te             .enable traps
         sa        a_static,a5,tmxp+xp_a0+(3*8)  .Save a_static in a_static of xp
                                       . that is used when EI is reentered.
         sbyts,2   x0,a5,x0,prs_comp   .Set initialization complete, this module
                                       . can now be reenetered by restarting the
                                       . running EI with P set to
                                       . 'osp$prepare_os_environment' and MPS set
                                       . to exchange package at TMXP.

.        Environment is now set up to allow traps, enable traps.

         cpyxs     x0,x0

         addpxq    a9,x0,complete_function  .return address for function complete.
         brdir     a9,x0               .return.
         page
..
.        ixp - Initializes the EI exchange packages.  Space is also reserved
.              for the ring 1 stack for each exchange package.
.
.        INPUT:
.                  a5 = pointer to first byte of EI code segment.
.                  a7 = response buffer address.
.                  a9 = return address.
.                  a_csf = pointer to area for exchange packages and stacks
.                          that are to be initialized.
.                  a_static = pointer to static shared variables.
.                  x7 = current response buffer length.
.                  xc = number of processors.
.
.        OUTPUT:
.                  (a7) = RMAs of exchange packages initialized.
.                  a_csf = pointer region right after last stack reserved.
.                  x7 = byte length of response buffer.
.

ixp      bss       0                   .Initialize exchange package.
         entp      x5,2
         sbyts,1   x5,a5,x0,tmxp+xp_tef  .Set traps enabled in initial xp temporarily.
         entp      x3,0                .indicate CPU 0

.        If concurrent CPUs (C170 can run in both CPUs) on a non-S1 mainframe,
.        then the external interrupt bit must be set in the monitor mask register
.        in the job exchange package.

         lbyts,1   x2,a_static,x0,dual_170  .get concurrent CPU flag
         entp      x1,2
         brrne     x1,x2,ixp5          .if not non-S1 concurrent CPUs
         entp      x5,1                .set the external interrupt bit
         entp      x0,0                .interrupt bit is bit 0
         sbit      x5,a5,tjxp+xp_mm+1,x0

.        Loop to initialize monitor and job exchange package and stacks.

ixp5     bss       0
         tpage     x5,a_csf
         sbyts,4   x5,a7,x7,0          .return RMA of monitor xp.
         incr      x7,4

.        Move monitor and job exchange packages to MPS or JPS respectively.
.        Some values in exchange packages are initialized.  This is done
.        for each CPU.

         movb,a5,x0  a_csf,x1  0,9,17*8,tmxp  0,9,17*8,0  .copy monitor package
         movb,a5,x0  a_csf,x1  0,9,18*8,tmxp+xp_sta  0,9,18*8,xp_sta

.        Update values in moved monitor exchange package.

         la        a8,a5,ei_monitor_pva
         sa        a8,a_csf,xp_p
         addpxq    a8,x0,mcbp          .update trap pointer
         sa        a8,a_csf,xp_tp
         sa        a_static,a_csf,xp_a0+3*8
         addaq     a8,a_csf,sf_monitor_stack      .Set monitor stack frame TOS pva.
         sa        a8,a_csf,xp_a0      .store register A0
         sa        a8,a_csf,xp_rn1     .store TOS Ring 1
         addaq     a_wrk,a_csf,sf_wrk
         sa        a_wrk,a_csf,xp_a0+0d(16)*8  .Set AD to work area in stack segment.
         addaq     a_jps,a_csf,sf_jxp
         sa        a_jps,a_csf,xp_a0+0b(16)*8  .Set AB to pva of job exchange package.
.
         movb,a5,x0  a_jps,x1  0,9,17*8,tjxp  0,9,17*8,0  .create job exchange
                                                          . package.
         movb,a5,x0  a_jps,x1  0,9,18*8,tmxp+xp_sta  0,9,18*8,xp_sta

.        Update values in moved job exchange package.

         addpxq    a8,x0,ocbp          .update trap pointer
         sa        a8,a_jps,xp_tp
         addaq     a8,a_csf,sf_job_stack  .job stack PVA
         sa        a8,a_jps,xp_a0      .store register A0
         sa        a8,a_jps,xp_rn1     .store TOS Ring 1

.        If processing a CPU other than CPU 0 and if running on non-S1 concurrent
.        CPUs, then the exchange package P address must be set to 76(8)*8.

         brreq     x3,x0,ixp10         .if currently processing CPU0
         entp      x1,2
         brrne     x1,x2,ixp10         .if not non-S1 concurrent CPUs
         ente      x5,ccpadd
         sbyts,4   x5,a_jps,x0,xp_p+2
ixp10    bss       0
         entp      x3,1                .indicate not CPU 0
         addaq     a_csf,a_csf,sf_size
         decx      xc,1
         brxgt     xc,x0,ixp5          .if more sfsa's to preset
         entp      x5,0
         sbyts,1   x5,a5,x0,tmxp+xp_tef  .reset traps disabled in initial xp.
         brdir     a9,x0               .Return.



         ref       osp$a170_fatal_error
osp$afe  address   p,osp$a170_fatal_error
         ref       osp$abort_a170_job
osp$aaj  address   p,osp$abort_a170_job
         page
..
.        re_ei - EI has been reentered by CTI.  Initialize environment to wait
.        for CTI requests.
.
.        INPUT:
.                  a5 = pointer to first byte of EI code segment.
.                  a_static = pointer to common EI variables in stack.
.                  x_flc = last byte offset + 1 of OS code segment.
.
.        OUTPUT:
.                  Environment initialized to wait for CTI requests.
.
.        EXIT:
.                  Exit to wait_for_request.
.

re_ei    bss       0
         addpxq    a8,x0,pcbp          .trap pointer for processing CTI requests.
         entl      x0,r_tp
         lbyts,1   xc,a5,x0,nop        .number of processors.
         la        a_csf,a5,mxp0_p     .address of monitor xp for cpu 0.
         cpyax     x3,a8
         entp      x1,0                .initialize exchange package pointer index.
         cpyaa     a7,a_tos            .use tos for response buffer.
         entp      x7,0                .index for first entry in response buffer.
         ente      x2,9a(16)           .clear global priviledge in 170 code segment
                                       . segment table entry.  This is used as the
                                       . concurrent 170 monitor interlock flag.
         cpyxs     x3,x0               .update trap pointer in active exchange
                                       . package.
         sbyts,1   x2,a5,x0,os_seg
         addpxq    a9,x0,re_ei5        .Set return address.
         brreq     x0,x0,ixp           .Initialize EI exchange packages.

.        Zero out the area for saving failing job mode exchange packages in the
.        work area for each monitor exchange package.  Do not want to leave
.        residue around that could be confusing when looking at dumps.

re_ei5   bss       0
         la        a7,a5,mxp0_p        .address of monitor xp for cpu 0.
         lbyts,1   xc,a5,x0,nop        .number of processors.
         entp      x5,0
         la        a9,a7,xp_a0+(0d(16)*8)  .a_wrk from monitor xp.
         ente      x9,xpsw-1           .index of last word to zero out.
re_ei10  bss       0
         sxi       x5,a9,x9,sf_save_job  .zero word.
         decx      x9,1
         brxge     x9,x0,re_ei10       .if area not zeroed out.
         decx      xc,1                .decrement number of processors.
         addaq     a7,a7,sf_size       .address of monitor xp for next processor.
         brxge     x0,xc,re_ei15       .if all processor save areas initialized.
         la        a9,a7,xp_a0+(0d(16)*8)  .a_wrk from monitor xp.
         ente      x9,xpsw-1           .index of last word to zero out.
         brreq     x0,x0,re_ei10       .initialize for next processor.

re_ei15  bss       0
         entl      x0,r_te
         la        a_csf,a5,tmxp+xp_a0+(1*8)   .Reset CSF to initial value.
         cpyxs     x0,x0               .enable traps.
         brreq     x0,x0,wait_for_request  .go wait for CTI requests.

         page
..
.        scan_cm   check central memory for unrecovered hardware errors.
.
.        ENTRY:
.                  a_rac = OS segment pointer.
.                  a_static = pointer to static shared variables.
.                  x_flc = last byte offset + 1 of OS field length.
.                  x7 = 0, response buffer length.
.
.        EXIT:
.                  a7 = response buffer address.
.                  a9 = reentry address on continue function.
.                  x7 = byte length of response buffer.
.

scan_cm  bss       0
         addaq     a7,a_tos,sf_job_stack-sf_monitor_stack
         addpxq    a9,x0,sca2          .re-entry address on continue
         entp      xa,0
         cpyxx     x9,x7               .index of last entry in response buffer.
         sx        x7,a7,0             .zero out first entry in response buffer.
sca1     lbyts,8   x1,a_rac,xa,0       .try to read cm
sca2     incr      xa,8
         sbyts,4   xa,a5,x0,cti_req+4  .tell cti of address being checked
         brrgt     x_flc,xa,sca1
         brreq     x0,x0,complete_function
         page
..
.        check_cm  run a memory test on central memory.
.
.        ENTRY:
.                  a_rac = OS segment pointer.
.                  a_static = pointer to static shared variables.
.                  x_flc = last byte offset + 1 of OS field length.
.                  x7 = 0, response buffer length.
.
.        EXIT:
.                  a7 = response buffer address.
.                  a9 = reentry address on continue function.
.                  x7 = byte length of response buffer.
.

check_cm bss       0
         addaq     a7,a_tos,sf_job_stack-sf_monitor_stack
         addpxq    a9,x0,che2
         entp      xa,0
         entn      xb,1
         cpyxx     x9,x7               .index of last entry in response buffer.
         sx        x7,a7,0             .zero out first entry in response buffer.
che1     shfx      x2,xa,x0,-3
         sxi       xb,a_rac,x2,0
         lxi       x1,a_rac,x2,0
         brrne     x1,xb,che3          .if data does not compare
che2     incr      xa,8
         sbyts,4   xa,a5,x0,cti_req+4  .tell cti of address being checked
         brrgt     x_flc,xa,che1       .if more to preset
         brreq     x0,x0,complete_function
.
che3     lxi       x1,a5,x_flc,0       .cause page fault
         page
..
.        continue  Continue the previous function where it left off.
.
.        ENTRY:
.                  a9 = 0, response buffer length.
.                  x7 = 0, response buffer length.
.
.        EXIT:
.                  a7 = response buffer address.
.                  x7 = 0, response buffer length.
.                  First word of response buffer is set to zero.
.

continue bss       0
         addaq     a7,a_tos,sf_job_stack-sf_monitor_stack
         lx        x9,a7,rbl*8         .last entry in response buffer.
         sx        x9,a7,0             .set first entry in response buffer to
                                       . last entry to avoid returning
                                       . duplicate errors.
         cpyxx     x9,x7               .index of last entry in response buffer.
         brdir     a9,x0               .re-enter routine
         page
..
.        fetch_frc fetch free running counter.
.
.        ENTRY:
.                  x7 = 0, response buffer length.
.
.        EXIT:
.                  a7 = response buffer address.
.                  x7 = byte length of response buffer.
.

fetch_frc bss      0
         addaq     a7,a_tos,sf_job_stack-sf_monitor_stack
         entp      x7,8
         cpytx     x1,x0               .read free running counter
         sx        x1,a7,0
         brreq     x0,x0,complete_function

         page
..
.        calculate new free running counter value.
.
.        ENTRY:
.                  a5 = pointer to requests.
.
.        EXIT:
.                  returned result parameter is the new frc value.
.

cnf      bss       0
         entp      x0,0
         entc      x1,0024
         addpxq    a9,x0,cnf1
         brreq     x0,x0,cwc           .convert hdw wcc to seconds
cnf1     cpyxx     x6,x3
         entc      x1,0016             .mrt wcc
         addpxq    a9,x0,cnf2
         brreq     x0,x0,cwc           .convert mrt wcc to seconds
cnf2     cpyxx     x7,x3
         brxgt     x7,x6,bad_year      .if mrt > hdw time
         lbyts,1   x1,a5,x0,cti_req+26 .hdw wcc year
         lbyts,1   x2,a5,x0,cti_req+18 .mrt wcc year
         brxne     x1,x2,cnf3          .if not same year
         subx      x6,x3
         lx        x1,a5,cti_req+8     .mrt frc
         lx        xc,a5,million
         mulx      x6,xc
         addx      x1,x6
         sx        x1,a5,cti_req+32    .store new frc
         entp      x2,0
         sbyts,2   x2,a5,x0,cti_req    .clear function code
         brreq     x0,x0,wait_for_request   .return
cnf3     entc      x1,0024             .hdw wcc
         addpxq    a9,x0,cnf4
         brreq     x0,x0,norm          .normalize hdw year
cnf4     cpyxx     x8,x3               .hdw year
         entc      x1,0016             .mrt wcc
         addpxq    a9,x0,cnf5
         brreq     x0,x0,norm          .normalize mrt year
cnf5     cpyxx     x9,x3               .mrt year
         entp      x5,0                .year days
         cpyxx     x3,x8
         subx      x3,x9
         entp      x4,1
         brreq     x3,x4,cnf8          .if delta years = 1 year
         cpyxx     x2,x8               .end year
         cpyxx     x3,x9               .start year
         incr      x3,1
cnf6     cpyxx     xa,x3
         entp      x4,4
         divx      xa,x4
         mulxq     xa,xa,4
         brreq     xa,x3,cnf_leap      .if leap year
         addrq     x5,x5,365
cnf7     incr      x3,1
         brreq     x2,x3,cnf8          .start = end years
         brreq     x0,x0,cnf6          .next year
cnf_leap addrq     x5,x5,366
         brreq     x0,x0,cnf7
cnf8     lx        xc,a5,sec_day
         mulx      x5,xc               .seconds in year
         lx        xb,a5,sec_year
         lbyts,1   x2,a5,x0,cti_req+18 .mrt year
         entp      x4,4
         divx      x2,x4
         mulxq     x2,x2,4
         lbyts,1   x4,a5,x0,cti_req+18 .mrt year
         brreq     x2,x4,cnf9          .if leap year
         brreq     x0,x0,cnf10
cnf9     lx        xe,a5,sec_day
         addx      xb,xe
cnf10    subx      xb,x7               .seconds in year - mrt seconds
         addx      xb,x5               .seconds in potential years in between
         addx      xb,x6               .total seconds from mrt wcc to hdw wcc
         lx        x1,a5,cti_req+8     .mrt frc
         addx      x1,xb
         lx        xc,a5,million
         mulx      x1,xc
save_res sx        x1,a5,cti_req+32    .return new frc value
         entp      x2,0
         sbyts,2   x2,a5,x0,cti_req    .clear function code
cnf11    brreq     x0,x0,wait_for_request .return
bad_year entp      x1,0
         brreq     x0,x0,save_res


         page
..
.        calculate validity of free running counter value.
.
.        ENTRY:
.                  a5 = pointer to requests.
.
.        EXIT:
.                  returned result parameter is 1 if valid.
.                  returned result parameter is zero if value is invalid.
.

cfv      bss     0
         cpytx   x1,x0                 .read free running counter
         lx      x2,a5,cti_req+8       .get mrt frc
         brxge   x1,x2,cfv1            .if hdw frc >= mrt frc
cfv0     entp    x1,0                  .mark as invalid
         brreq   x0,x0,cfv2
cfv1     lx      x3,a5,delta           .2 weeks
         addx    x2,x3
         brxgt   x1,x2,cfv0            .if greater than delta also invalid
         entp    x1,1                  .mark as valid
cfv2     sx      x1,a5,cti_req+32
         entp    x0,0
         entp    x2,0
         sbyts,2 x2,a5,x0,cti_req      .clear function code
         brreq   x0,x0,wait_for_request .return

         page
..
.        convert wall clock format to seconds.
.
.        ENTRY:
.                  a5 = pointer to requests.
.                  x1 = offset to wcc cti request word.
.
.        EXIT:
.                  x3 = total seconds
.
cwc      bss     0
         lbyts,1 x2,a5,x1,cti_req+3    .get month
         decr    x2,1                  .for table look up
         cpyxx   x3,x1
         entc    x1,0012
         brrgt   x2,x1,osp$ei_halt     .invalid month
         cpyxx   x1,x3
         mulxq   x2,x2,2
         lbyts,2 x3,a5,x2,day_table    .number of days in year by month
         lbyts,1 x2,a5,x1,cti_req+2    .year
         entp    x4,4
         divx    x2,x4
         mulxq   x2,x2,4
         lbyts,1 x4,a5,x1,cti_req+2    .year
         brreq   x2,x4,leap            .if leap year
seconds  lbyts,1 x2,a5,x1,cti_req+7    .seconds
         lbyts,1 x5,a5,x1,cti_req+6    .minutes
         mulrq   x5,x5,60
         addx    x2,x5
         lbyts,1 x5,a5,x1,cti_req+5    .hours
         mulrq   x5,x5,3600
         addx    x2,x5
         lbyts,1 x5,a5,x1,cti_req+4    .days in this month
         decr    x5,1                  .not through this day yet
         addx    x3,x5                 .add to total days this year
         lx      xc,a5,sec_day
         mulx    x3,xc
         addx    x3,x2
         brdir   a9,x0                 .return
leap     lbyts,1 x2,a5,x1,cti_req+3    .get month
         decx    x2,3
         brxge   x2,x0,leap1
         brreq   x0,x0,seconds         .if before feb 29
leap1    addrq   x3,x3,1               .bump for leap year
         brreq   x0,x0,seconds         .calculate total seconds

day_table bss    0
         vfd,16  0                     .jan 1
         vfd,16  31                    .feb 1
         vfd,16  59                    .mar 1
         vfd,16  90                    .apr 1
         vfd,16  120                   .may 1
         vfd,16  151                   .jun 1
         vfd,16  181                   .jly 1
         vfd,16  212                   .aug 1
         vfd,16  243                   .sep 1
         vfd,16  273                   .oct 1
         vfd,16  304                   .nov 1
         vfd,16  334                   .dec 1
entries  equ     ($-day_table)/2


..
.        normalize year in clock format to 19xx or 20xx.
.
.        ENTRY:
.                  a5 = pointer to requests.
.                  x1 = offset to wcc cti request word.
.
.        EXIT:
.                  x3 = year.
.

norm     bss     0
         lbyts,1 x2,a5,x1,cti_req+2    .get year
         entc    x1,90
         cpyxx   x3,x2
         subx    x3,x1
         brxge   x3,x0,norm1           .if before year 2000
         addrq   x3,x2,2000            .20xx
         brdir   a9,x0                 .return
norm1    addrq   x3,x2,1900            .19xx
         brdir   a9,x0                 .return

         page
..
.        calculate the page table length.
.
.        ENTRY:
.                  a5 = pointer to requests.
.
.        EXIT:
.                  returned result parameter is the page table length.
.

cpi      bss       0
         lx        x1,a5,cti_req+8     .Get CM size in Mb (1Mb to 1Gb)
         lx        x2,a5,cti_req+16    .Page size (2k, 4k, 8k, 16k)
         lx        x3,a5,cti_req+24    .Page table entries (2, 4, 8 entries per page)
         divx      x1,x2               .(CM size / Page size)
         mulx      x1,x3               .* Page table entries
         cpyxx     x2,x1               .Insure modulo 2
         entp      x3,1
         subx      x2,x3               .PTL - 1
         addx      x2,x1               .PTL + PTL - 1
         entp      x3,0                .Initialize shift count
cpi1     shfc      x2,x2,x0,1          .Find most significant bit
         incr      x3,1                .Bump shift count
         brxge     x2,x0,cpi1          .If not found yet
         ente      x2,63
         subx      x2,x3               .Form final shift count
         entp      x1,1
         shfc      x1,x1,x2,0          .Final PTL value
         sx        x1,a5,cti_req+32    .Result
         entp      x2,0
         sbyts,2   x2,a5,x0,cti_req    .clear function code
         brreq     x0,x0,wait_for_request .Return

         page
..
.        osp$halt_ei - This procedure hangs EI when an error condition is encountered
.                  that can not be recovered from.  During initialization the address
.                  of this procedure is stored in 'pva_halt_ei'.  This procedure
.                  moves an error message to the EICB and then hangs EI.
.
.        ENTRY:
.                  a_static = PVA of common working storage area.
.
.        EXIT:     Branch to osp$ei_halt which is a loop on itself.
.

osp$halt_ei bss    0
         la        a_dscb,a_static,pva_of_dscb  .PVA of EICB.
         ente      x1,eml              .set message length.
         lx        x6,a_dscb,d7ty
         isob      x6,x6,x0,52*64+5    .EICB version number.
         decx      x6,4
         brrgt     x0,x6,ohe5          .If EICB version less than 4.

.        EICB version of 4 or greater, has space for a message in the EICB.  Move the
.        message to the EICB and set values to reflect message length and indicate
.        that there is a new message.

         addpxq    a6,x0,damm          .PVA of error message.
         cpyxx     x0,x1               .set source field length.
         movb,a6,x0  a_dscb,x1  1,9,0,0  1,9,0,dfcm+(1*8)  .move message to EICB.
         sbyts,2   x1,a_dscb,x0,dfcm+2 .set message length.

.        Update the processor and model number in the message stored in the EICB.

         entl      x0,r_pid
         entx      x1,c'C'             .processor 0 value.
         cpysx     x6,x0               .get processor number.
         entl      x0,r_eid
         addx      x6,x1               .set character for processor.
         cpysx     x0,x0               .element id.
         sbyts,1   x6,a_dscb,x0,dfcm+(1*8)+14  .update processor in message.
         isob      x6,x0,x0,(40*64)+3  .high order 4 bits of model number.
         entp      x2,9
         entx      x1,c'0'
         brrge     x2,x6,ohe2          .if digit 0 through 9.
         decx      x6,10
         entx      x1,c'A'
ohe2     bss       0
         addx      x6,x1               .convert digit to ascii.
         sbyts,1   x6,a_dscb,x0,dfcm+(1*8)+15  .update high order 4 bits of
                                       . model number.
         isob      x6,x0,x0,(44*64)+3  .low order 4 bits of model number.
         entx      x1,c'0'
         brrge     x2,x6,ohe4          .if digit 0 through 9.
         decx      x6,10
         entx      x1,c'A'
ohe4     bss       0
         addx      x6,x1               .convert digit to ascii.
         lbyts,2   x1,a_dscb,x0,dfcm+6  .set new message in EICB.
         sbyts,1   x6,a_dscb,x0,dfcm+(1*8)+16  .update low order 4 bits of
                                       . model number.
         incx      x1,1
         sbyts,2   x1,a_dscb,x0,dfcm+6 .indicate new message in EICB.
ohe5     bss       0
         brreq     x0,x0,osp$ei_halt   .Hang EI.

eml      equ       24                  .error message length, bytes.

.        Define error message put in EICB.  The error code, "damm" is defined
.        in deck cti$dft_analysis_codes.  If more messages are added the codes
.        should be added to that deck.  The fault symptom code format is
.        'Temmxxx' with the following meaning:
.                   'T' - Environment interface (EI) identifier.
.                   'e' - Processor number, C through F.
.                   'mm' - Model number.
.                   'xxx' - Error code.

damm     vfd,eml*8  c'         ERR=Temm60D    '  .170 mcr fault in monitor mode.
         page
..
.        trap_handler  - This trap handler is set up to process traps for uncorrected
.                  memory errors, all traps are assumed to be uncorrected memory
.                  errors.  The RMA of memory errors are rounded to the minimum page
.                  size boundary.
.
.        INPUT:
.                  a7 = address of response buffer.
.                  a9 = return address if response buffer not full.
.                  x7 = index into response buffer for next entry.
.                  x9 = index of last entry in response buffer.
.                  xa = RMA of bad address.
.
.        EXIT:
.                  x7 = index of next entry in response buffer.
.                  x9 = index of last entry in response buffer.
.                  Return to (a9) if response buffer not full.  Returns to
.                  'complete_function' if buffer is full.
.

         align     0,8
trap_handler bss   0
         lbyts,4   x8,a7,x9,0          .last RMA stored.
         isom      x1,x0,0*64+54
         andx      xa,x1               .round to minimum page size boundary.
         brreq     x8,x1,tmp5          .if in same page as previous error.
         sbyts,4   xa,a7,x7,0          .store rma of bad address
         cpyxx     x9,x7               .save index of last entry.
         incr      x7,4
         ente      x1,(rbl+1)*8
         brrgt     x1,x7,tmp5          .if buffer is not full.
         addpxq    a9,x0,complete_function
tmp5     cpyaa     a0,a2               .update tos register
         pop
         ente      x0,r_te
         cpyxs     x0,x0               .set tef
         brdir     a9,x0
         PAGE
.*******************************************************************
.
.        EI segment and exchange package tables plus some other values
.        that are needed upon reentry of EI.
.
.******************************************************************

nop      bss       1                   .number of processors.
mxp0_p   bss       6                   .pointer to monitor xp, processor 0.

.
.        pva of ei_monitor.
.
         ref       osp$monitor_mode_ei
ei_monitor_pva address  p,osp$monitor_mode_ei

.
.        SEGMENT DESCRIPTOR TABLE.
.
         align     0,8
         def       osp$segment_table
osp$segment_table bss 0
pt_seg   vfd,16    8a11(16)            .Page table entry
pt_asid  vfd,16    4000(16)
         vfd,32    0
.
         vfd,16    0000(16)            .Null segment entry
         vfd,16    00000(16)
         vfd,32    0
.
os_cb_sg vfd,16    0da11(16)           .OS cache bypass segment
         vfd,16    0ffff(16)
         vfd,32    0
.
OS_SEG   vfd,16    9a11(16)            .OS segment entry
OS_ASID  vfd,16    0ffff(16)
         vfd,32    0
.
SF_SEG   vfd,16    8a11(16)            .Stack segment entry
SF_ASID  vfd,16    0c000(16)
         vfd,32    0
.
EI_SEG   vfd,16    0be11(16)           .EI segment entry
EI_ASID  vfd,16    8000(16)
         vfd,32    0
         space     4
.        Define the page table segment ring=1, segment=0
.
pgtable  section   working,read+write
         use       pgtable
pt_pva   bss       0
ring1    bss       0
         use       #lastsec
         space     4
.        Define the OS cache bypass segment ring=1, segment=3
.
os_cache_bypass section   working,read+write
         use       os_cache_bypass
os_cb_pva bss      0
         use       #lastsec
         space     4
.        Define the OS segment ring=1, segment=3
.
osseg    section   working,read+write+execute
         use       osseg
os_pva   bss       0
         use       #lastsec
         space     4
.        Define the stack segment ring=1, segment=4
.
stackseg section   working,read+write
         use       stackseg
stack_pva bss      0
         use       #lastsec
         space     4
.        code based pointers to trap handlers.
.
PCBP     address   ce,trap_handler
         ref       osp$mtr_trap_handler
MCBP     address   ce,osp$mtr_trap_handler
         ref       osp$os_trap_handler
OCBP     address   ce,osp$os_trap_handler
         SPACE     4
..
.        DEFINE NIL POINTER ATTRIBUTE.
.
NIL      EQU       20078
UM       EQU       0FE00(16)           .USER MASK
MM       EQU       mcr_mask            .MONITOR MASK VALUE
PIT      EQU       0FFFF(16)           .INITIAL PIT VALUE
..
.        DEFINE MACRO FOR ADDRESS REGISTERS IN THE C180 EXCHANGE PACKAGE.
.
         PROC
adrg     PNAME
F:(0)    vfd,16    F:(1,1)             .UPPER 16 BIT FIELD
         DO        SC:(F:(2,1))=0
         DO        SN:(F:(2,0))=SN:(NIL)
         vfd,20,28 0FFFF8(16),0        .NIL POINTER
.        ADVF      1
         ELSE
         ADDRESS   R,F:(2,0)
.        ADVF      1
         DEND
         ELSE
         vfd,16,32 F:(2,0),F:(2,1)
.        ADVF      2
         DEND
         PEND
         page
..
.        Define initial contents of EI monitor exchange package.
.        This is the xp that is initially entered by CTI for
.        initialization and when reentering EI.  Some registers
.        are initialized for reentering EI during the initialization.
.

         align     0,16
TMXP     BSS       0                   .MONITOR EXCHANGE PACKAGE
         def       osp$monitor_exchange_package
osp$monitor_exchange_package bss 0
         adrg,0    osp$prepare_os_environment           .P
         adrg,0    stack_pva           .VMID,UVMID, A0
         adrg,0    NIL                 .FLAGS, TRAPS DISABLED, A1
         adrg,UM   NIL                 .USER MASK, A2
         adrg,MM   stack_pva           .MONITOR MASK, A3, a_static
         adrg,0    NIL                 .UCR, A4
         adrg,0    ei_pva              .MCR, A5
         adrg,0    pt_pva              .KEYPOINT CLASS, LPID, A6
         adrg,0    NIL                 .KEYPOINT MASK, A7
         adrg,0    NIL                 .KEYPOINT CODE, A8
         adrg,0    NIL                 .KEYPOINT CODE, A9
         adrg,PIT  NIL                 .PIT, AA
         adrg,PIT  NIL                 .PIT, AB, a_jps
         adrg,0    os_cb_pva           .AC, a_rac
         adrg,0    NIL                 .AD, a_wrk
         adrg,0    os_pva              .AE, a_nos
         adrg,6    NIL                 .PTL, AF, a_dscb
         bss       17*8                .reserve space for X registers
toslst   adrg,0    NIL                 .segment table address
         adrg,osp$segment_table pcbp   .STA, TRAP POINTER
         adrg,0    NIL                 .DEBUG INFORMATION
         adrg,1    NIL                 .LARGEST RING NUMBER, TOS1
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         adrg,0    NIL
         space     4
.
.        JOB EXCHANGE PACKAGE.
.
TJXP     BSS       0                   .JOB PROCESS EXCHANGE PACKAGE
         def       osp$job_exchange_package
osp$job_exchange_package bss 0
         adrg,0    os_pva              .C170 P
         adrg,0100(16)  NIL            .job stack PVA
         adrg,2    NIL                 .FLAGS, TRAP ENABLES, A1
         adrg,UM   NIL                 .USER MASK, A2
         adrg,MM   ring1+0             .MONITOR MASK, rac
         adrg,0    ring1+200000(8)     .UCR, flc
         adrg,0    ring1               .A5
         adrg,0    ring1               .A6
         adrg,0    ring1               .A7
         adrg,0    ring1               .A8
         adrg,0    ring1               .A9
         adrg,PIT  ring1               .PIT, AA
         adrg,PIT  ring1               .PIT, AB
         adrg,0    ring1               .AC
         adrg,0    ring1               .AD
         adrg,0    ring1               .AE
         adrg,6    ring1               .STL, AF

         end       osp$prepare_os_environment
