1 " ***********************************************************
   2 " *                                                         *
   3 " * Copyright, (C) Honeywell Bull Inc., 1987                *
   4 " *                                                         *
   5 " * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   6 " *                                                         *
   7 " * Copyright (c) 1972 by Massachusetts Institute of        *
   8 " * Technology and Honeywell Information Systems, Inc.      *
   9 " *                                                         *
  10 " ***********************************************************
  11 
  12 " HISTORY COMMENTS:
  13 "  1) change(87-06-22,Fawcett), approve(87-06-23,MCR7734),
  14 "     audit(87-07-14,Farley), install(87-07-17,MR12.1-1043):
  15 "     Change the checking for the "mylock" on the ptl for after the first stac
  16 "     instructions indicates that the lock was in fact locked.
  17 "                                                      END HISTORY COMMENTS
  18 
  19 
  20 " " " " " " " "" " " " " " " " " " " " " " " " " " " " " " " " " " " "
  21 "
  22 "         page_fault
  23 "
  24 "         This is the major procedure of Multics page control. For details, see
  25 "         the Storage System PLM, Order Number AN61.
  26 "
  27 "         Coded 1/70 by S.Webber
  28 " Last Modified (Date and Reason):
  29 "         Modified by S.Webber 07/01/71 to add page multilevel
  30 "         Modified by S.Webber 07/01/72 for followon
  31 "         Modified by S.Webber 10/01/73 to merge with privileged code
  32 "         Modified by B. Greenberg 06/10/74 for IOBM and put all cam/lock_ptl in page.
  33 "         Modified by B. Greenberg 11/12/74 for overlap-lookahead core control.
  34 "         Modified by B. Greenberg 02/05/75 for new storage system.
  35 "         Modified by S. Webber 02/05/76 for new reconfiguration
  36 "         Modified by B. Greenberg 03/08/76 for waiting on PTL
  37 "         Modified by B. Greenberg 05/13/76 for pdme's with uid/pageno
  38 "         Modified by B. Greenberg 12/76 for core_queue_man delay queue.
  39 "         Modified by B. Greenberg 3/31/77 for disk_emergency and new page_error.
  40 "         Modified by B. Greenberg 5/03/77 for page$pcleanup, aste.damaged.
  41 "         Modified by RE Mullen 5/13/77 for concurrent scheduler
  42 "         Modified by B. Greenberg 8/77 for pc_recover_sst, misc. cleanups.
  43 "         Modified by B. Greenberg 9/20/77 for disk offline waiting.
  44 "         Modified by B. Greenberg 3/15/78 for large sst, ptw.phm1
  45 "         Modified by B. Greenberg 5/1/78 for parity errors.
  46 "         Modified by D. Spector 2/20/79 for 18-bit unsigned quota
  47 "         Modified by B. Greenberg 2/79 for variable write_limit
  48 "         Modified by B. Greenberg 2/79 for 8-cpu port expander
  49 "         Modified by J. A. Bush 3/80 to store fault time in machine conditions
  50 "         Modified by B. Greenberg 6/23/80 for loop & unlock meters
  51 "         Modified by J. A. Bush 8/80 for the DPS8/70M CPU
  52 "         Modified by E.N. Kittlitz (per WOS) to not update PF count on gtus segments.
  53 "         Modified by E.N. Kittlitz 11/17/80 for new dtu/dtm calculation.
  54 "         Modified by J. Bongiovanni 1/81 for fault_counters
  55 "         Modified by M. Pierret 11/80 to use page pinning algorithm
  56 "         Modified by J. Bongiovanni 2/81 to remove cam/cache code
  57 "         Modified by W. Olin Sibert, 2/26/81, for ADP conversion, phase one
  58 "         Modified by C. Hornig, January 1982, to only CAM if segment accessible.
  59 "         Modified by J. Bongiovanni, January 1982, to remove PML code, add
  60 "             extended page fault trace type
  61 "         Modified by J. Bongiovanni, February 1982, for stocks
  62 "         Modified by E. N. Kittlitz, 6/21/82, summer solstice sacrifice of core map.
  63 "         Modified by J. Bongiovanni, July 1982, scs$trouble_processid, scavenger
  64 "         Modified by J. Bongiovanni, October 1982, synchronized segment support,
  65 "              don't decrement quota through zero
  66 "         Modified by E. N. Kittlitz (Massachusetts agent for W.O. Sibert) to pin those pages again.
  67 "         Modified by Keith Loepere, October 1983, for paged unpaged dseg and
  68 "              for bug fix to find_core loop.
  69 "         Modified by R. Coppola 10/13/83 to meter DF1 on per-cpu basis and
  70 "         added code to meter cache errors when mc_trace'ing
  71 "         Modified by BIM 83-12-03 for pgt_ IPS signal.
  72 "         Modified by TO 84-10-17 to remove write_limit and disk_run'ing.
  73 "         Modified by Keith Loepere, December 1984, for covert channel
  74 "              detection and a little cleanup.
  75 "         Modified by Keith Loepere, January 1985, for updated covert
  76 "              channel detection.
  77 "         Modified by Keith Loepere, January 1985, for fix to aste.records race.
  78 "         Modified by Tom Oke, February 1985, to remove a missed write_limit
  79 "              and disk run.
  80 "^L
  81 "         The following entries exist within this procedure (given by entry name to "page"):
  82 "
  83 "         done      used by the paging DIMs to signal the completion
  84 "                   of an I/O request.
  85 "
  86 "         enter_data places an entry into the per-process trace table
  87 "
  88 "         fault     transferred to upon page faults from the fault vector
  89 "
  90 "         lock_ptl  used to lock the page table lock
  91 "
  92 "         pccleanup used to get a page out of core
  93 "
  94 "         pread     used to read a page into core
  95 "
  96 "         pwrite    used to write a page out of core
  97 "
  98 "         reset_working_set is obsolete and does nothing
  99 "
 100 "         trace_marker places a user marker entry into the per-process
 101 "                   trace table
 102 "
 103 "         unlock_ptl used to unlock the page table lock
 104 "
 105 "
 106 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 107 
 108 "
 109 " ^L
 110 "
 111 " The very beginning
 112 "
 113           name      page_fault
 114 
 115 
 116           entry     wait_return,pmut_unlock_ptl
 117           entry     ptl_wait_return
 118 
 119           segdef    check_accessible              " See whether anyone can access segment
 120           segdef    cleanup_page                  " Evict one page from memory
 121           segdef    cme_offsets                   " Core map ITS pointers, 1 per cme word
 122           segdef    cme_0,cme_bp,cme_fp           " ITS to word 0 of cme
 123           segdef    cme_1,cme_devadd,cme_flags    " ITS to word 1 of cme
 124           segdef    cme_2,cme_astep,cme_ptwp      " ITS to word 2 of cme
 125           segdef    cme_3,cme_pin_counter,cme_synch_page_entryp       " ITS to word 3 of cme
 126 
 127           segdef    delete_mm_frame               " Clear out and deconfigure main memory frame
 128           segdef    disk_offline_event            " Wait event for disk offline
 129           segdef    disk_offlinep                 " Check whether disk is offline
 130           segdef    done                          " Post completion of I/O
 131           segdef    done_                         " Post completion with PTL locked
 132           segdef    enter_data                    " Enter per-process trace data
 133           segdef    fault                         " Page Fault entry
 134           segdef    find_core_                    " Find a frame of core
 135           segdef    init_savex                    " Init x7 save stack
 136           segdef    init_savex_bb                 " Init x7 save stack, set bb -> sst
 137           segdef    lock_ptl                      " Lock PTL
 138           segdef    lock_ptl_ext                  " Lock PTL from outside ALm PC
 139           segdef    lock_ptl_no_lp                " Lock PTL, don't save lp
 140           segdef    my_lp                         " lp for bound_page_control
 141           segdef    notify_return                 " Side-door return from pxss$notify_page
 142           segdef    page_fault_error              " Call to page_error - fatal
 143           segdef    pcleanup                      " Entry to get a page out of core
 144           segdef    pf_prs                        " Pointer to saved prs on page fault
 145           segdef    pf_scuinfo                    " Pointer to SCU data on page fault
 146           segdef    pre_page_info                 " Obsolete
 147           segdef    pread                         " Entry to read a page
 148           segdef    pwrite                        " Entry to write a page
 149           segdef    read_page_abs                 " Same as read_page, but OOPV not allowed
 150           segdef    reset_working_set             " Obsolete
 151           segdef    savex                         " Save x7 in save stack for recursive use
 152           segdef    set_up_abs_seg                " Setup abs_seg_1
 153           segdef    thread_in                     " Thread CME as MRU
 154           segdef    thread_lru_ext                " Thread CME as LRU, ouside of ALM PC
 155           segdef    thread_out                    " Thread CME out of used list
 156           segdef    thread_to_lru                 " Thread CME as LRU
 157           segdef    trace_marker                  " Add user marker to per-process trace
 158           segdef    trace_restart_fault           " Add restart_fault to per-process trace
 159           segdef    trace_scheduling              " Add reschedule to per-process trace
 160           segdef    trace_signaller               " Add signaller to per-process trace
 161           segdef    unlock_ptl                    " Unlock PTL
 162           segdef    unlock_ptl_ext                " Unlock PTL, outside of ALM PC
 163           segdef    unsavex                       " Pop save stack, tra 0,x7
 164           segdef    unsavex_1                     " Pop save stack, tra 1,x7
 165           segdef    unsavex_2                     " Pop save stack, tra 2,x7
 166           segdef    write_page                    " Write page out if necessary
 167 "^L
 168 
 169           include   page_regs
 170 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 171 "
 172 "         Temporary storage, INCLUDE files, and constants
 173 "
 174 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 175 
 176 
 177           link      prds_link,prds$
 178           link      abs_seg1_link,abs_seg1$
 179 
 180           include   stack_frame
 181           include   stack_header
 182           include   trace_types
 183           include   sys_trouble_codes
 184           include   mode_reg
 185           include   pxss_page_stack
 186           include   page_error_types
 187           include   page_info
 188           include   apte
 189           include   sst
 190           include   tc_meters
 191           include   wcte
 192           include   sdw
 193           include   ptw
 194           include   add_type
 195           include   aste
 196           include   cmp
 197           include   mc
 198           include   null_addresses
 199           include   static_handlers
 200           include   device_error
 201           include   mctseg
 202           include   fault_vector
 203           include   unpaged_page_tables
 204 "^L
 205 "         check for wild transfers to bound_page_control|0
 206 
 207           tsx5      page_fault_error    "ERROR - TRA TO PAGE|0"
 208           tsx5      page_fault_error    "ERROR - TRA TO PAGE|1"
 209 "
 210 "
 211 "         The following code (located at bound_page_control|2) is used for
 212 "         hardware debugging to make it easy to restart the last page
 213 "         fault via restoring the machine conditions and doing an RCU.
 214 "
 215           epplp     my_lp,*             restore page's linkage
 216           eppap     pds$page_fault_data
 217           tra       restart_fault
 218 
 219           dec       0         " (bpc|5) -- address_mask used to be here
 220 
 221 "         This location (bound_page_control|6) is left unused so that
 222 "         obsolete patches of run limit (write_limit) will not crash system.
 223 obsolete_wlim:
 224           dec       0
 225 
 226           even
 227 pf_prs:   its       -1,1
 228 pf_scuinfo:
 229           its       -1,1
 230 my_lp:
 231           its       -1,1
 232 
 233 cme_offsets:                            " set up by initialize_faults.
 234 cme_0:
 235 cme_bp:
 236 cme_fp:   its       -1,0
 237 
 238 cme_1:
 239 cme_devadd:
 240 cme_flags:
 241           its       -1,1
 242 
 243 cme_2:
 244 cme_ptwp:
 245 cme_astep:
 246           its       -1,2
 247 
 248 cme_3:
 249 cme_pin_counter:
 250 cme_synch_page_entryp:
 251           its       -1,3
 252 
 253 sdw_bits:                     " Bits for abs-seg SDW -- it is
 254                               " Address 0, read/write, one unpaged page
 255 
 256           iftarget  L68       " SDW is different format for each
 257             vfd     18/0,18/sdw.valid
 258             vfd     1/0,14/(1024/16)-1,3/sdw.read+sdw.write,18/sdw.unpaged
 259           ifend
 260 
 261           iftarget  ADP
 262             vfd     18/0,18/sdw.valid
 263             vfd     14/(1024/16)-1,4/0,18/sdw.read+sdw.write+sdw.unpaged
 264           ifend
 265 
 266 channel_mask_set:
 267           oct       17,17
 268 
 269 unnull_mask:
 270           zero      -1-ptw.nulled,-1    mask to resurrect an address
 271 
 272           even
 273 null:     its       -1,1
 274 pc_signal_arglist:
 275           vfd       18/6,18/4,18/0,18/0
 276 
 277 "*********************************************************************
 278 "*********************************************************************
 279 "*********************************************************************
 280 "*********                                                  **********
 281 "*********          HERE ARE THE CONSTANTS ... AND          **********
 282 "*********          HERE BEGINS THE CODE OF PAGE_FAULT.     **********
 283 "*********                                                  **********
 284 "*********************************************************************
 285 "*********************************************************************
 286 "*********************************************************************
 287 "^L
 288 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 289 "
 290 "         Subroutines:
 291 "
 292 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 293 
 294 lock_ptl:
 295           sprilp    sp|stack_frame.lp_ptr we don't do a normal 'entry' so ...
 296 lock_ptl_no_lp:
 297           epbpbb    sst$                bb -> SST through out page
 298           lda       pds$processid       lock the page table lock
 299           stac      sst|sst.ptl
 300           tze       ptl_ok              branch if we think locked it
 301           read_clock                    meter time waiting for lock
 302           cmpa      sst|sst.ptl         check for mylock on page table lock
 303           tze       page_error$ptl_mylock  complain if lock already set
 304           staq      pds$arg_1
 305           lda       pds$processid       get set to lock again
 306 ptl_repeat:
 307           stac      sst|sst.ptl         hurry up and wait
 308           nop
 309           nop
 310           tnz       ptlfail             locked, see if wait needed
 311           read_clock
 312           sbaq      pds$arg_1
 313           adaq      sst|sst.loop_lock_time
 314           staq      sst|sst.loop_lock_time
 315           increment sst|sst.loop_locks  meter times we had to loop lock
 316 ptl_ok:
 317           lda       pds$processid       did we lock ok?
 318           cmpa      sst|sst.ptl
 319           tze       *+2
 320           tsx5      page_fault_error    "ERROR - PTL STAC FAILED"
 321           tra       0,.ret
 322 
 323 ptlfail:
 324           cmpx      .ret,pft_lret,du    locking for page fault?
 325           tnz       ptl_repeat          no, loop some more
 326           read_clock                    account for partial pf time
 327           sbaq      pds$time_1          account for partial pf time
 328           adaq      tc_data$cpu_pf_time account for partial pf time
 329           staq      tc_data$cpu_pf_time account for partial pf time
 330           tra       pxss$ptl_wait       yes, wait for lock
 331 
 332 ptl_wait_return:                        "return location from pxss$ptl_wait
 333           eppap     pds$page_fault_data
 334           read_clock                    account for rest of pf time
 335           staq      pds$time_1          account for rest of pf time
 336           tra       masked_switched_legal
 337 
 338 pmut_unlock_ptl:
 339           push
 340           tsx       .2ret,init_savex_bb
 341           tsx       .ret,unlock_ptl
 342           eppap     sp|stack_frame.arg_ptr,*
 343           sprisp    sb|stack_header.stack_end_ptr
 344           eppsp     sp|stack_frame.prev_sp,*
 345           tra       pmut$unwire_unmask
 346 unlock_ptl_ext:
 347           push
 348           tsx       .2ret,init_savex_bb
 349           tsx       .ret,unlock_ptl     unlock the ptl
 350           tra       return
 351 
 352 
 353 unlock_ptl:
 354           tra       core_queue_man$unlock_ptl  Hoo, boy!
 355 
 356 lock_ptl_ext:
 357           eax       .ret,.rt
 358           tra       lock_ptl_no_lp
 359 .rt:      short_return
 360 
 361 non_fatal_error:
 362           eax5      -1,.ret
 363           tsx       .2ret,page_error$non_fatal_error
 364           tra       0,.ret
 365 
 366 page_fault_error:
 367           eax5      -1,5                set x5 to point to actual call to subroutine
 368           tra       page_error$page_fault_error  die
 369 
 370 init_savex_bb:
 371           epp       sst,sst$
 372 init_savex:
 373           eaa       save_stack          get address of save stack base
 374           ora       stack_size*64,dl    set up a tally word for storing into save_stack
 375           sta       stackp              stash this away
 376           tra       0,.2ret             return to the caller
 377 
 378 
 379 savex:
 380           stx       .ret,stackp,id      store x7 in save stack using tally word
 381           ttf       0,.2ret             return to the caller if tally not runout
 382           tsx5      page_fault_error    "ERROR - SAVE STACK OVERFLOW"
 383 
 384 unsavex:
 385           ldx       .ret,stackp,di      pop value of x7 (also updating tally word properly)
 386           tra       0,.ret
 387 unsavex_1:
 388           ldx       .ret,stackp,di      pop value of x7 (also updating tally word properly)
 389           tra       1,.ret
 390 
 391 "^L
 392 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 393 "                                                           "
 394 "         Subroutines to manage used list threading         "
 395 "                                                           "
 396 "                                                           "
 397 "                                                           "
 398 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 399 
 400 "
 401 "         Move an entry to least-recently-used place
 402 "
 403 thread_to_lru:
 404 
 405 
 406 "         assumes .cme -> cme
 407 
 408           cmpx      .cme,sst|sst.usedp  see if already at lru point
 409           tze       0,.ret              leave it if so
 410 
 411           szn       cme_fp,*.cme make sure threaded in (could be postpurge os)
 412           tmoz      0,.ret
 413 
 414 
 415 "
 416 "         Load pointers to current brothers, thread out.
 417 "
 418           ldx       .nxt,cme_fp,*.cme next
 419           lxl       .lst,cme_bp,*.cme previous
 420 
 421           cmpx      .cme,sst|sst.wusedp see if write point is on .cme
 422           tnz       *+2
 423           stx       .nxt,sst|sst.wusedp make writes start at next
 424 
 425 "         Thread out
 426 
 427           stx       .nxt,cme_fp,*.lst successor(last) = successor
 428           sxl       .lst,cme_bp,*.nxt last(successor) = last
 429 
 430 "         Move to usedp
 431 
 432 mv_to_usedp:
 433           ldx       .nxt,sst|sst.usedp  point to successor to be
 434 
 435 "         See if usedp at wusedp. If so, back up wusedp.
 436 
 437           cmpx      .nxt,sst|sst.wusedp see if wusedp = usedp
 438           tnz       *+2                 no, not equal.
 439           stx       .cme,sst|sst.wusedp our cme is new wused
 440 
 441           stx       .cme,sst|sst.usedp  in any case, our cme is new used.
 442 
 443 thread_behind:
 444           lxl       .lst,cme_bp,*.nxt point to last to be
 445 
 446 "         Thread to .cme
 447 
 448           stx       .cme,cme_fp,*.lst successor (last) = cme
 449           sxl       .cme,cme_bp,*.nxt last (successor) = cme
 450 
 451 "         Thread cme to environment
 452 
 453           stx       .nxt,cme_fp,*.cme successor (cme) = successor
 454           sxl       .lst,cme_bp,*.cme last (cme) = last
 455 
 456           tra       0,.ret
 457 
 458 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
 459 "                                                           "
 460 "         Thread a cme out of the used list.                "
 461 "                                                           "
 462 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
 463 
 464 thread_out:
 465 
 466 "         Point to environment
 467 
 468           ldx       .nxt,cme_fp,*.cme successor = successor (cme)
 469           tpnz      *+2
 470           tsx5      page_fault_error    "ERROR - THREADING OUT UNTHREADED CME"
 471 
 472           lxl       .lst,cme_bp,*.cme last = last (cme)
 473 
 474 "         Make sure replacement and writing pointers are not
 475 "         looking at .cme.
 476 
 477           cmpx      .cme,sst|sst.usedp
 478           tnz       *+2
 479           stx       .nxt,sst|sst.usedp move usedp to successor if so
 480 
 481           cmpx      .cme,sst|sst.wusedp
 482           tnz       *+2
 483           stx       .nxt,sst|sst.wusedp
 484 
 485 "         Thread out
 486 
 487           sxl       .lst,cme_bp,*.nxt last (successor) = last
 488           stx       .nxt,cme_fp,*.lst successor (last) = successor
 489 
 490           stz       cme_fp,*.cme
 491           tra       0,.ret
 492 
 493 "^L
 494 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
 495 "                                                           "
 496 "         Thread an unthreaded entry to lru                 "
 497 "                                                           "
 498 "                                                           "
 499 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
 500 
 501 thread_in:
 502           szn       cme_fp,*.cme make sure not threaded in already
 503           tmoz      mv_to_usedp
 504           tsx5      page_fault_error    "ERROR - THREADING IN THREADED CME"
 505 
 506 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
 507 "
 508 "         Thread an unthreaded entry to MRU.              "
 509 "                                                           "
 510 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
 511 
 512 thread_in_mru:
 513           ldx       .nxt,sst|sst.wusedp thread in behind wusedp.
 514           szn       cme_fp,*.cme     make sure not threaded in
 515           tmoz      thread_behind       move behind wusedp
 516           tsx5      page_fault_error    "ERROR - MRU THREADING THREADED CME"
 517 
 518 "
 519 "         External entry to thread to lru.
 520 "
 521 thread_lru_ext:
 522           eppbp     ap|2,*              ap -> cmep
 523           eax       .cme,bp|0,*
 524           epp       sst,sst$            set up sst ptr
 525           tsx       .ret,thread_to_lru
 526           short_return
 527 "^L
 528 
 529           inhibit   on
 530           even
 531 meter_virtual_time:
 532           lca       1,dl                check for recursive metering
 533           asa       pds$vtime_count     ..
 534           tpl       0,.ret              yes, do no more
 535           read_clock                    get current value of CPU time
 536           adl       96,dl                         add in correction delta
 537           sbaq      pds$cpu_time        ..
 538           sbaq      pds$time_v_temp     get time used for this fault/interrupt
 539           staq      pds$time_v_temp
 540           adaq      pds$virtual_delta   save as virtual time increment
 541           staq      pds$virtual_delta   ..
 542           ldaq      pds$time_v_temp     also calculate total vcpu
 543           adaq      tc_data$+delta_vcpu
 544           staq      tc_data$+delta_vcpu
 545           tra       0,.ret
 546           inhibit   off
 547 
 548 set_up_abs_seg:
 549           lda       core_add
 550           als       coreadd_to_sdw.ls   shift core addr into sdw pos
 551           eaq       0                   clear q-reg
 552           oraq      sdw_bits            turn on other interesting bits
 553           eppap     abs_seg1$           get pointer to core area
 554           ldx       .tem,lp|abs_seg1_link get segno of abs_seg1
 555           adlx      .tem,lp|abs_seg1_link multiply by 2
 556           staq      dseg$,.tem          store in descriptor segment
 557           cams
 558           tra       0,.2ret
 559 
 560 store_pattern:
 561           tsx       .2ret,set_up_abs_seg get abs_seg1 ready
 562           ldaq      =vo36/777666333222,o36/444000111555
 563           staq      ap|0                and store it into the page
 564           staq      ap|1022             ..
 565           tra       0,.ret
 566 
 567 check_pattern:
 568           tsx       .2ret,set_up_abs_seg
 569           ldaq      =vo36/777666333222,o36/444000111555
 570           cmpaq     ap|0                if the same we have trouble
 571           tze       1,.ret              take error return
 572           cmpaq     ap|1022             try the last 2 words
 573           tnz       0,.ret              ok if not the same
 574           tra       1,.ret              bad news if the same
 575 
 576 clear_core:
 577           tsx       .2ret,set_up_abs_seg make abs_seg1 point to core_add
 578           eax       .tem,4096           zero out 4096 characters
 579           mlr       (),(pr,rl),fill(0)
 580           desc9a    0,0
 581           desc9a    ap|0,x0             .tem
 582           tra       0,.ret
 583 
 584 check_for_zero:                         " assumes abs_seg1 setup
 585           eppap     abs_seg1$
 586           eax       .tem,4096           number of characters in a page
 587           cmpc      (),(pr,rl),fill(0)
 588           desc9a    0,0
 589           desc9a    ap|0,x0             .tem
 590           tze       1,.ret
 591           tra       0,.ret
 592 
 593 
 594 " ^L
 595 "
 596 "         The following subroutine (reset_mode_reg) is called before masking down.
 597 "         It therefore must be inhibited.
 598 "
 599           inhibit   on
 600 reset_mode_reg:
 601           rsw       2                             get cpu type in a
 602           als       mc.cpu_type_shift             get the CPU type
 603           ana       mc.cpu_type_mask,du
 604           stca      ap|mc.cpu_type_word,70        store in machine conditions
 605           arl       18-mc.cpu_type_shift          position in au lower
 606           eax4      0,au                          copy to x4
 607           szn       pds$mc_trace_sw               is this process tracing machine conditions?
 608           tpl       no_trace_mc                   xfer if no
 609           szn       pds$mc_trace_seg              Does user want to trace all M. Cs?
 610           tze       cp_hregs                      xfer if seg number zero
 611           lda       ap|mc.scu.ppr.psr_word        look at the psr
 612           ana       scu.ppr.psr_mask,du           and out  everything except psr
 613           cmpa      pds$mc_trace_seg              compare psr to object we are tracing
 614           tze       cp_hregs                      xfer if psr = object we are tracing
 615           lda       ap|mc.scu.tpr.tsr_word        look at tsr
 616           ana       scu.tpr.tsr_mask,du           and out everthing except tsr
 617           cmpa      pds$mc_trace_seg              compare tsr to object we are tracing
 618           tnz       no_trace_mc                   do not trace if psr and tsr don't have seg
 619 cp_hregs: scpr      ap|mc.fim_temp,01             save fault register
 620           ldaq      ap|mc.fim_temp                note that scpr does D.P. store and
 621           sta       ap|mc.fault_reg               stores zeroes in mc.fault_reg
 622           qrl       mc.cpu_type_shift             make room for cpu type
 623           orq       ap|mc.cpu_type_word           or in cpu type
 624           stcq      ap|mc.cpu_type_word,70        store cpu type and ext fault reg
 625           lda       prds$processor_tag            get cpu num
 626           xec       cache_ctr_tab,al              lb=> per-cpu cache err ctrs
 627           lda       ap|mc.fault_reg               reload PFR
 628           ana       =o10,dl                       cache dir parity (bit 32)?
 629           tze       check_efr                     no, go check EFR
 630           aos       lb|1                          yes, increment the per-cpu ctr
 631 check_efr:
 632           anq       mc.ext_fault_reg_mask,du      mask unwanted bits OFF
 633           tze       no_efr                        no bits on, bypass
 634           qls       2                             get EFR bits in Q 1-17
 635           eaa       0                             set up A as incrementer
 636 efr_loop:
 637           ada       1,dl                          increment EFR slot number
 638           qls       1                             is this bit on?
 639           tpnz      efr_loop                      no, but some other bit on
 640           tze       no_efr                        no more EFR bits
 641           aos       lb|1,al                       increment EFR counter
 642           tra       efr_loop                      look for nxt EFR bit
 643 
 644 no_efr:   lprplb    pds$mc_trace_buf              get packed ptr to wired trace buffer
 645           lxl5      lb|mctseg.hr_nxtad            x5 = rel ptr to next H. R. storage location
 646           cmpx5     lb|mctseg.hr_lim              do we have to roll over the trace?
 647           tmi       hr_roll                       xfer if no
 648           ldx5      lb|mctseg.hr_strt             yes, pick up initial storage location
 649           sxl5      lb|mctseg.hr_nxtad            store new location
 650 hr_roll:  eax5      mctseg.hr_size,5              increment storage location
 651           sxl5      lb|mctseg.hr_nxtad            set rel ptr to next H. R. storage location
 652           epplb     lb|-mctseg.hr_size,5          lp -> current HR storage location
 653           ldq       2,du                          get a 2 for stepping address
 654           eax6      4                             4 blocks of
 655 scpr1:    eax5      16                            16 history registers
 656           eax3      0                             set up for L68 CPU type initally
 657           cmpx4     1,du                          is this a DPS8/70M CPU?
 658           tnz       scpr2                         xfer if no, it is L68
 659           eax3      48                            yes, set up to skip first 48 hregs
 660           cmpx6     3,du                          DU hreg? Don't have one on DPS8/70M
 661           tnz       scpr2                         no, go execute it
 662           mlr       (),(pr),fill(0)               zero out this 32 word block
 663           desc9a    0,0
 664           desc9a    lb|64,32*4
 665           eax6      -1,6                          yes, skip it
 666 scpr2:    lda       scpr-1,6                      get correct instruction
 667           sta       ap|mc.fim_temp                save in stack
 668 scpr3:    xec       ap|mc.fim_temp                execute the instruction
 669           cmpx3     0,du                          are we through skipping hregs?
 670           tze       scpr4                         yes, go increment address
 671           eax3      -1,3                          no, skip another
 672           tra       scpr3                         and go execute scpr again
 673 
 674 scpr4:    asq       ap|mc.fim_temp                increment address of instruction
 675           eax5      -1,5                          count down
 676           tnz       scpr3                         more of this 16 double word block
 677           eax6      -1,6                          count down
 678           tnz       scpr1                         another kind of hreg
 679 
 680           eax5      64                            initially set clear count to 64
 681           cmpx4     1,du                          is this a DPS8/70M CPU?
 682           tze       *+2                           yes, clear all 64 hregs
 683           eax5      16                            no, clear only 16 hregs
 684           lcpr      0,03                          set all history regs to zero
 685           eax5      -1,5                          count down
 686           tpnz      *-2                           xfer if more to do
 687           eawplb    0
 688 trace_mc:
 689           lxl5      lb|mctseg.mc_nxtad            x5 = rel ptr to next M. C. storage loc
 690           cmpx5     lb|mctseg.mc_lim              do we have to roll over the trace?
 691           tmi       mc_roll                       xfer if no
 692           ldx5      lb|mctseg.mc_strt             yes, pick up initial storage location
 693           sxl5      lb|mctseg.mc_nxtad            store new location
 694 mc_roll:
 695           eax5      mctseg.mc_size,5              increment storage location
 696           sxl5      lb|mctseg.mc_nxtad            set rel ptr to next M. C. storage location
 697           epplb     lb|-mctseg.mc_size,5          lp -> current MC storage location
 698           mlr       (pr),(pr)                     move the data to wired buffer
 699           desc9a    ap|0,mctseg.mc_size*4
 700           desc9a    lb|0,mctseg.mc_size*4
 701 no_trace_mc:
 702           epplb     prds$cache_luf_reg            reset cache control reg
 703           lcpr      lb|0,02                       lcpr to reload luf and cache control
 704           lda       prds$mode_reg                 retrieve template mode reg
 705           ora       mr.enable_mr+mr.enable_hist,dl enable mode reg and hist regs
 706           sta       prds$mode_reg_enabled         save this mode reg value
 707           epplb     prds$mode_reg_enabled         get pointer to temp mode reg value
 708           lcpr      lb|0,04                       reload the mode register
 709           tra       0,.ret                        return to caller
 710 
 711 scpr:     scpr      lb|0,40                       OU History Regs for L68, OU/DU for DPS8
 712           scpr      lb|32,20                      CU History Regs
 713           scpr      lb|64,10                      DU History Regs for L68, not used for DPS8
 714           scpr      lb|96,00                      APU History Regs
 715 
 716 cache_ctr_tab:
 717           epplb     wired_hardcore_data$cpu_a_cache_err_ctr_array
 718           epplb     wired_hardcore_data$cpu_b_cache_err_ctr_array
 719           epplb     wired_hardcore_data$cpu_c_cache_err_ctr_array
 720           epplb     wired_hardcore_data$cpu_d_cache_err_ctr_array
 721           epplb     wired_hardcore_data$cpu_e_cache_err_ctr_array
 722           epplb     wired_hardcore_data$cpu_f_cache_err_ctr_array
 723           epplb     wired_hardcore_data$cpu_g_cache_err_ctr_array
 724           epplb     wired_hardcore_data$cpu_h_cache_err_ctr_array
 725 
 726 fault_ctr_table:
 727           eppab     wired_hardcore_data$cpu_a_flt_ctr_array
 728           eppab     wired_hardcore_data$cpu_b_flt_ctr_array
 729           eppab     wired_hardcore_data$cpu_c_flt_ctr_array
 730           eppab     wired_hardcore_data$cpu_d_flt_ctr_array
 731           eppab     wired_hardcore_data$cpu_e_flt_ctr_array
 732           eppab     wired_hardcore_data$cpu_f_flt_ctr_array
 733           eppab     wired_hardcore_data$cpu_g_flt_ctr_array
 734           eppab     wired_hardcore_data$cpu_h_flt_ctr_array
 735 
 736           inhibit   off
 737 
 738 get_pvtx:
 739           lda       ast|aste.pvtx_word,.aste
 740           arl       aste.pvtx_shift
 741           ana       aste.pvtx_mask,dl
 742           sta       pvtx
 743           tra       0,.ret
 744 
 745 
 746 " ^L
 747 " " " " " " " " " " " " " " "
 748 "
 749 "         enter_data -- entry to add data to the 'system trace list'
 750 "         Call is:
 751 "
 752 "         call page$enter_data(data_word, type)
 753 "
 754 "         where data_word is a word value to be
 755 "         entered into the next available slot in the trace
 756 "         list. If type = 0 (page fault type) then a return is
 757 "         done and the entry is not placed in the list.
 758 "
 759 " " " " " " " " " " " " " " " " " " " " "
 760 
 761           include   sys_trace
 762 
 763 trace_signaller:
 764           epplp     my_lp,*             set linkage pointer
 765           lda       pds$condition_name  get first four characters of name
 766           ldq       pds$condition_name+1
 767           lls       9                   shift out ACC count field
 768           ldq       signaller_type,du   get coded type
 769           tsx       .ret,enter
 770           tra       lb|0                return via special code
 771 
 772 trace_restart_fault:
 773           epplp     my_lp,*
 774           eaa       0                   code for restart is zero
 775           ldq       restart_fault_type,du
 776           tsx       .ret,enter
 777           tra       lb|0                return via special code
 778 
 779 trace_marker:
 780           lda       ap|2,*              get char string to use as marker
 781           ldq       marker_type,du      set type appropriately
 782           tsx       .ret,enter
 783           short_return
 784 
 785 trace_scheduling:
 786           eaa       0                   code word is all zeros
 787           ldq       reschedule_type,du  get type code
 788           tra       enter
 789 
 790 enter_data:
 791           lda       ap|2,*              pick up the data_word
 792           ldq       ap|4,*              make sure non-zero type given
 793           qls       30                  left justify
 794           tze       short_return        return if illegal type given
 795           tsx       .ret,enter
 796 short_return:
 797           short_return
 798 
 799 return:   return
 800 
 801 "
 802 "         Subroutine to enter a page fault into the system-trace list
 803 "
 804 page_util_enter:
 805           stx       .aste,temp          astep
 806           eax       .tem,-aste_size,.ptw PTW addr - ASTE size
 807           sblx      .tem,temp           page number
 808           anx       .tem,=o377,du       only significant bits
 809 
 810           szn       tc_data$post_purge_switch     are we post-purging?
 811           tze       extended_page_util_enter      no -- we can stuff more data into trace
 812 
 813 "         We are post-purging, so we need old format trace entry
 814 
 815           ldq       pds$page_fault_data+mc.scu.tpr.tsr_word  get segno in q
 816           eaa       0,.aste             get astep in a-reg
 817           arl       18
 818           lls       18                  fabricate entire code word
 819           eaq       0,.tem              page number (low order bits) in upper
 820           tra       enter
 821 
 822 extended_page_util_enter:
 823           lda       pds$page_fault_data+mc.scu.ppr.psr_word PPR in AU
 824           ana       =o7777,du           Low-order bits only
 825           arl       18                  PPR in AL
 826           ldq       pds$page_fault_data+mc.scu.ilc_word     IC in QU
 827           anq       -1,du               strip out garbage (indicators)
 828           lls       18+6                1st 30 bits or first word
 829           sta       temp
 830           lda       pds$page_fault_data+mc.scu.ppr.psr_word PPR in AU
 831           ldq       pds$page_fault_data+mc.scu.cu_stat_word CU status bits
 832           canq      scu.cu.if,dl        fault on instruction fetch
 833           tnz       *+2                 yes - use PPR
 834           lda       pds$page_fault_data+mc.scu.tpr.tsr_word no - use TSR
 835           ana       =o7777,du           Low-order bits only
 836           arl       18                  segno in AL
 837           eaq       0,.tem              pageno in QU
 838           qls       18-8
 839           lrl       6
 840           qrl       6
 841           ora       temp
 842           orq       extended_page_fault_type,du
 843 
 844 enter:    eppap     pds$trace           get pointer to trace structure
 845           ldx       .tem,ap|trace.next_free_word get current index to next free slot
 846           staq      ap|trace.data,.tem  save coded information
 847           read_clock
 848           sbaq      ap|trace.ttime      get incremental time
 849           stq       ap|trace.temp       save in temporary
 850           adaq      ap|trace.ttime      recalculate last fault time
 851           staq      ap|trace.ttime
 852           ldq       ap|trace.temp       retrieve delta-time
 853           qrl       6                   in terms of 64 micro-seconds
 854           cmpq      =o177777,dl         see if time is too large
 855           tmi       *+2                 no, use it
 856           ldq       =o177777,dl         yes, time is too large, use standard large value
 857           orsq      ap|trace.data+1,.tem OR time value into trace entry
 858           eax       .tem,2,.tem         bump entry index
 859           cmpx      .tem,ap|trace.last_available_word  check for wrap-around
 860           tnz       trace.no_wrap       not now, though
 861           eax       .tem,0              we wrapped. reset to beginning
 862 trace.no_wrap:
 863           cmpx      .tem,ap|trace.threshold_word signal?
 864           tnz       trace.no_signal     nope
 865           lda       ap|trace.send_ips_word  Signals enabled?
 866           cana      trace.send_ips,dl
 867           tze       trace.no_signal
 868           eppbp     pds$apt_ptr,*       no need to lock, we use stacq
 869 trace.retry_ips:
 870           lda       sys_info$pgt_mask   This cannot recurse,
 871           ora       bp|apte.ips_message since we only test EQUAL to
 872           ldq       bp|apte.ips_message threshold. The pgt_ trace
 873           stacq     bp|apte.ips_message will be GREATER.
 874           tnz       trace.retry_ips
 875           lda       1,dl                set ring alarm
 876           sta       pds$alarm_ring      store in simulated spot
 877           lra       pds$alarm_ring      set for real
 878 trace.no_signal:
 879           stx       .tem,ap|trace.next_free_word
 880 
 881           tra       0,.ret
 882 
 883 
 884 reset_working_set:
 885           short_return
 886 
 887 pre_page_info:
 888           stz       ap|4,*              pre-page calls
 889           stz       ap|6,*              paging device page faults
 890           stz       ap|8,*              no pre-paging
 891           short_return
 892 "^L
 893 
 894 " quota primitives - check for RQO, decrement quota, increment quota
 895 
 896 check_quota:
 897           lda       ptw|0                         inspect ptw
 898           cana      add_type.non_null,dl          see if not_null address
 899           tze       check_quota.real_null
 900           als       0
 901           tpl       0,.ret                        real address, return
 902 
 903 check_quota.real_null:
 904           tsx       .2ret,type_terminal_quota
 905           tra       *+2                           seg quota
 906           tra       0,.ret                        dir quota, skip it for now
 907 
 908           eax       .tem,0,.aste                  loop up parents
 909 quota_c:  lxl       .tem,ast|aste.par_astep,.tem  get father
 910           cana      ast|aste.tqsw_word,.tem       see if terminal
 911           tze       quota_c                       no, loop up
 912 
 913           szn       pds$quota_inhib               special consideration?
 914           tnz       0,.ret                        yes, return
 915 
 916           lda       entry_sw                      don't check on read entry
 917           cmpa      read_entry,dl
 918           tze       0,.ret                        read entry, don't check
 919 
 920           lda       ap|mc.scu.tpr.trr_word        get ring of faulting reference
 921           cana      scu.tpr.trr_mask,du           see if in ring 0
 922           tze       0,.ret                        yes, don't check quota
 923 
 924           ldx       .2ret,ast|aste.used,.tem      check seg quota for over
 925           cmpx      .2ret,ast|aste.quota,.tem
 926           tnc       0,.ret                        not over quota, return
 927           lda       PAGE_ERROR_RQO,dl             type of error to signal
 928           eppab     ast|0,.tem                    ASTE of quota account
 929           tra       errquit
 930 
 931 " subtract 1 from quota cell
 932 
 933 reset_quota:
 934           eax       .tem,0,.aste                  start at current aste
 935           tsx       .2ret,type_terminal_quota     find quota parent
 936           lxl       .tem,ast|aste.par_astep,.tem  seg quota applies to parent
 937 
 938 quota_r:  xec       quota.lx,ql                   fetch correct cell
 939           tze       *+3                           don't decrement thru 0
 940           sblx      .2ret,1,du
 941           xec       quota.sx,ql                   save back
 942           cana      ast|aste.tqsw_word,.tem       stop at terminal account
 943           tnz       0,.ret
 944           lxl       .tem,ast|aste.par_astep,.tem  parent cell
 945           tra       quota_r
 946 
 947 " add 1 to quota cell
 948 
 949 bump_quota:
 950           lda       aste.fmchanged,du             turn on fmchanged
 951           orsa      ast|aste.fmchanged_word,.aste
 952 
 953           eax       .tem,0,.aste                  start at current aste
 954           tsx       .2ret,type_terminal_quota     find quota parent
 955           lxl       .tem,ast|aste.par_astep,.tem  seg quota applies to parent
 956 
 957 quota_b:  xec       quota.lx,ql                   fetch correct cell
 958           adlx      .2ret,1,du
 959           xec       quota.sx,ql                   save back
 960           cana      ast|aste.tqsw_word,.tem       stop at terminal account
 961           tnz       0,.ret
 962           lxl       .tem,ast|aste.par_astep,.tem  parent cell
 963           tra       quota_b
 964 
 965 bump_quota_covert_check:
 966 
 967 " Add 1 to quota cell, also check that there exists a terminal quota node
 968 " before the first upgraded node.  This should be used only for dirs,
 969 " so that we don't require terminal dir quota for upgraded dirs.
 970 
 971           lda       aste.fmchanged,du             turn on fmchanged
 972           orsa      ast|aste.fmchanged_word,.aste
 973 
 974           eax       .tem,0,.aste                  start at current aste
 975           tsx       .2ret,type_terminal_quota     find quota parent
 976           lxl       .tem,ast|aste.par_astep,.tem  seg quota applies to parent
 977           ora       aste.multi_class,du           we will "stop" on terminal
 978 "                                                 node or upgraded node
 979           stz       temp                          assume terminal-ness
 980 
 981 quota_bc: xec       quota.lx,ql                   fetch correct cell
 982           adlx      .2ret,1,du
 983           xec       quota.sx,ql                   save back
 984           cana      ast|aste.tqsw_word,.tem       look at tqsw and multi_class
 985           tze       quota_bc_next                 neither upgraded nor terminal
 986 
 987           lxl       .2ret,ast|aste.tqsw_word,.tem terminal half-word
 988           canx      .2ret,quota.tq_mask,ql
 989           tnz       quota_bc_term                 terminal found
 990           sta       temp                          upgraded found first
 991 quota_bc_next:
 992           lxl       .tem,ast|aste.par_astep,.tem  parent cell
 993           tra       quota_bc
 994 
 995 quota_bc_term:
 996           lda       temp
 997           tnz       0,.ret                        upgraded found first
 998           tra       1,.ret                        terminal-ness okay
 999 
1000 " determines type of quota (seg/dir), returns to call+(1/2) so depending
1001 " also sets a to have corresponding mask bit for tqsw,
1002 " q to have a 0/1 corresponding to (seg/dir)
1003 
1004 type_terminal_quota:
1005           lda       ast|aste.nqsw_word,.aste special seg?
1006           cana      aste.nqsw,dl        ..
1007           tnz       0,.ret              leave whole biz if so
1008 
1009           cana      aste.dirsw,dl       dirsw_word same as nqsw_word
1010           tnz       type.dir_quota
1011 
1012           lda       aste.tqsw,dl        seg quota type
1013           ldq       0,dl
1014           tra       0,.2ret
1015 type.dir_quota:
1016           lda       aste.tqsw/2,dl
1017           ldq       1,dl
1018           tra       1,.2ret
1019 
1020 quota.lx: ldx       .2ret,ast|aste.used,.tem      instructions to load desired
1021           lxl       .2ret,ast|aste.used,.tem      quota cell
1022 
1023 quota.sx: stx       .2ret,ast|aste.used,.tem      instructions to store desired
1024           sxl       .2ret,ast|aste.used,.tem      quota cell
1025 
1026 quota.tq_mask:
1027           arg       aste.tqsw                     values for checking for tqsw
1028           arg       aste.tqsw/2                   in bump_quota_covert_check
1029 "^L
1030 " " " " " " " " " " " " " " " " " " " " " " " "
1031 "
1032 "         check_accessible    subroutine to check if any processor can access
1033 "                             the page in question. This tells us whether to
1034 "                             clear all the AM's.
1035 "
1036 " " " " " " " " " " " " " " " " " " " " " " " "
1037 
1038 check_accessible:
1039           ldx       .tem,ast|aste.strp,.aste      " get aste.strp
1040           tnz       0,.2ret             " must CAM
1041           lda       ast|aste.hc_sdw_word,.aste    " check for HC segment
1042           cana      aste.hc_sdw,du      " aste.hc_sdw?
1043           tnz       0,.2ret             " yes, CAM
1044                                         " volmap_seg_word same as hc_sdw_word
1045           cana      aste.volmap_seg,dl  " aste.volmap_seg?
1046           tnz       0,.2ret             " yes, CAM
1047           tra       1,.2ret             " we save some connects!
1048 "^L
1049 " " " " " " " " " " " " " " " " " " " " " " " " "
1050 "
1051 "         Routines to check for pages of synchronized segments
1052 "
1053 "
1054 "         On evict, do housekeeping
1055 "
1056 "             tsx7  check_synch_cleanup
1057 "
1058 "         On write, check if page must be held
1059 "
1060 "            tsx7    check_for_synch_hold
1061 "            <return if page cannot be written>
1062 "            <normal return>
1063 "
1064 " " " " " " " " " " " " " " " " " " " " " " " " "
1065 
1066 
1067 check_synch_cleanup:
1068           lda       cme_flags,*.cme
1069           cana      cme.synch_held,dl             synchronized page
1070           tze       0,.ret                        no
1071           tra       page_synch$cleanup            return to 0,x7
1072 
1073 check_for_synch_hold:
1074           lda       ast|aste.synchronized_word,.aste
1075           cana      aste.synchronized,dl          synchronized page
1076           tze       1,.ret                        no
1077           tsx       .2ret,savex                   recursive use of x7
1078           tsx       .ret,page_synch$write         check whether we should write
1079           tra       unsavex                       do not write
1080           tra       unsavex_1                     write OK
1081 
1082 "^L
1083 " " " " " " " " " " " " " " " " " " " " " " " "
1084 "
1085 "         update_csl          subroutine to make sure the csl
1086 "                             for a segment is correct. It is called
1087 "                             when a page is found to be zero,
1088 "                             either by being modified to zeroes or
1089 "                             by being a non-modified null address.
1090 "
1091 " " " " " " " " " " " " " " " " " " " " " " " " "
1092 
1093 update_csl:
1094           stz       temp                zero out entire word
1095           stz       temp+1              and next as well
1096           eax       .tem,aste_size,.aste get a pointer to the page table
1097           stx       .tem,temp           save for now
1098           stx       .tem,temp+1
1099           eax       .tem,1,.ptw         get page number by subtracting base of PT from ptp
1100           sblx      .tem,temp           (add 1 to get csl )
1101           stx       .tem,temp
1102           lda       ast|aste.csl_word,.aste pick up csl of segment
1103           ana       aste.csl_mask_inner,du
1104           arl       aste.csl_shift-18   shift to upper a, right justified
1105           cmpa      temp                compare with page number
1106           tnz       0,.ret              not the same, don't change csl
1107           eax       .tem,-1,.ptw        start search at previous page
1108           cmpx      .tem,temp+1         end search at first page of segment
1109           tnc       up_csl.set_csl      done (at page zero)
1110           ldq       ptw.valid,dl                  get in core flag for compares
1111 csl_loop:
1112           canq      sst|0,.tem          is current page in core ?
1113           tnz       up_csl.set_csl      yes, stop and set csl here
1114           lda       sst|0,.tem          get ptw
1115           cana      add_type.non_null,dl is there a real address?
1116           tze       up_csl.dont_count
1117           als       0                   test sign
1118           tpl       up_csl.set_csl      real disk address
1119 up_csl.dont_count:
1120           eax       .tem,-1,.tem        go to previous PTW
1121           cmpx      .tem,temp+1         are we passed the start ?
1122           trc       csl_loop            no, loop back and check this page
1123 up_csl.set_csl:
1124 "update csl into AST entry
1125           eaa       1,.tem              get curerrent ptp (+1 to convert to csl format)
1126           sbla      temp+1              subtract out base of page table
1127           als       aste.csl_shift-18   shift to position in AST entry
1128           era       ast|aste.csl_word,.aste and store in AST entry
1129           ana       aste.csl_mask_inner,du
1130           ersa      ast|aste.csl_word,.aste
1131           tra       0,.ret              return
1132 
1133 " ^L
1134 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1135 "
1136 "         fault
1137 "
1138 "         This entry is transferred to from the fault vector when a page fault
1139 "         occurs. The pointers, registers, etc. must be saved...
1140 "
1141 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1142 
1143           even
1144 fault:
1145           inhibit   on
1146           spri      pf_prs,*
1147           eppap     pf_prs,*            get pointer to MC
1148           sreg      ap|mc.regs          save registers
1149           spl       ap|mc.eis_info
1150           epplp     my_lp,*             set up linkage pointer
1151           read_clock                    start metering
1152           staq      ap|mc.fault_time    save fault time in machine conditions
1153           staq      pds$time_1          and in pds
1154           aos       pds$vtime_count     check for recursive virtual metering
1155           tpnz      already_metering    ..
1156           sbaq      pds$cpu_time        calculate virtual time
1157           staq      pds$time_v_temp     save until RCU time
1158 already_metering:
1159           tsx       .ret,reset_mode_reg reset mode register (turn on history regs)
1160 
1161           rsw       0                   get set for possible tracing
1162           sta       sst$+sst.trace_sw
1163 
1164           lxl1      prds$processor_tag  get set for masking
1165           lprpab    scs$mask_ptr,1
1166           xec       scs$read_mask,1
1167           staq      ap|mc.mask
1168           ldaq      scs$sys_level
1169           xec       scs$set_mask,1
1170           xec       fault_ctr_table,1   AB => per-cpu fault ctr array
1171           aos       ab|0+FAULT_NO_DF1
1172           inhibit   off
1173 
1174           eppab     sp|0                save sp in ab
1175           eppsp     prds$+stack_header.stack_begin_ptr,*  get set for push macro
1176           epbpsb    sp|0                set stack base pointer
1177           push
1178 
1179           spriab    sp|stack_frame.prev_sp  now save previous sp
1180           lca       scu.ir.parm+1,dl    make sure parity mask is OFF
1181           ansa      ap|mc.scu.indicators_word
1182 
1183 "
1184 "         The following code checks to make sure we don't get a fault while
1185 "         we're on the PRDS.
1186 "
1187           lxl7      ap|mc.prs+6*2       however, if were not in ring 0, OK
1188           canx7     =o700000,du
1189           tnz       masked_switched_legal                   not in ring 0, OK
1190           ldx7      ap|mc.prs+6*2       get SP at time of fault
1191           cmpx7     lp|prds_link        compare segment number to that of PRDS
1192           tze       fault_while_on_prds bad news, return to bos
1193 masked_switched_legal:
1194 
1195           tsx       .2ret,init_savex    initialize save_stack for x7
1196           tsx       .ret,lock_ptl       lock the page table lock
1197 pft_lret:
1198 
1199           stz       entry_sw            fault entry, set switch
1200           stz       ap|mc.errcode       zero error code for later use
1201 
1202           eppap     pds$page_fault_data restore pointer to fault data
1203           epplb     dseg$               get pointer to descriptor segment
1204 
1205 "         If a page fault is taken during an instruction fetch then the CU status
1206 "         bit IF (instruction  fetch) will be ON.
1207 
1208           lxl1      ap|mc.scu.cu_stat_word Get CU status bits
1209           canx1     scu.cu.if,du        Is IF bit ON?
1210           tze       regular_page_fault  not on, must be normal one (so use TSR)
1211 
1212           lda       ap|mc.scu.ppr.psr_word For an IF page fault the PSR is valid
1213           lxl1      ap|mc.scu.apu_stat_word Reset x1 to APU status bits.
1214           tra       all_page_faults     Go join normal path
1215 regular_page_fault:
1216           lxl1      ap|mc.scu.apu_stat_word see what type of fault
1217           canx1     scu.apu.ptw+scu.apu.dsptw+scu.apu.ptw2,du is it a normal page fault?
1218           tnz       *+2                 if one of these bits is on we're OK
1219           tsx5      page_fault_error    "ERROR - BAD SCU DATA NO APU BITS"
1220           lda       ap|mc.scu.tpr.tsr_word This is the normal path. The segno is in TSR
1221 
1222 all_page_faults:
1223           ldq       ap|mc.scu.ca_word   page number is derived from CA field
1224           canx1     scu.apu.ptw2,du     is it a pre-page (decimal instruction)
1225           tze       *+2                 no, don't increment page number
1226           adlq      1024,du             yes, up the page number by 1
1227           ana       scu.tpr.tsr_mask,du leave just the segno in AU
1228           sta       temp                save for bound comparison.
1229           als       1                   multiply by sdw size
1230           eax       .tem,0,au           put in x0
1231           lda       lb|1                get DSEG sdw bounds word (bound 377770)
1232           ora       =o7,du              convert bounds to max segno
1233           cmpa      temp                this is segno 377770000000
1234           tmi       bad_segno           Segno out of reason.
1235           stq       temp                save tsr word offset
1236           ldaq      lb|0                get addr of descriptor segment from its sdw (DBR)
1237           arl       sdw.add_shift       move to fixed bin
1238 "                                       see if dseg paged
1239           sbla      unpaged_page_tables$0+upt.sst_absloc    convert to page table pointer
1240           tmi       not_dseg            unpaged page tables are below sst
1241           eppbp     sst|0,al            make bp point to first page table word
1242           eaa       0,.tem              get two times segno
1243           arl       10                  get page number of dseg
1244 
1245           canx1     scu.apu.dsptw,du    Is this a page fault on the dseg?
1246           tnz       dseg_page_fault     Yes, skip the following code
1247 
1248           lda       ptw|0,au            get correct PTW for dseg
1249           cana      ptw.valid,dl                  ..
1250           tze       quit                there is fault, go take it
1251 not_dseg:
1252           ldaq      lb|0,.tem           look for seg-fault, get sdw of segment
1253           cana      sdw.valid,dl        see if directed fault set
1254           tze       quit                go handle seg-fault
1255           staq      pf_sdw              save access fields
1256           arl       36-24               move to fixed bin
1257           sbla      sst|sst.ptwbase     no seg-fault, get page table index
1258           eppbp     sst|0,al            get the astep (+aste_size)
1259           ldq       temp                get back word offset
1260           qrl       page_power          convert to page number
1261           tra       found_faulted_page  skip code for dseg faults
1262 
1263 dseg_page_fault:
1264           stq       pf_sdw+1            address word doesn't matter for dseg
1265           eaq       0,au                copy page number into q
1266 found_faulted_page:
1267           eax       .aste,ptw|-aste_size get real astep into x3
1268           eppbp     ptw|0,qu            adjust ptwp to point to the actual PTW
1269           eax       .ptw,ptw|0          and save it in x2
1270 
1271           ldq       ptw|0               get PTW in q-reg
1272           canq      ptw.valid,dl                  see if fault still exists
1273           tnz       quit                no, return
1274           canq      ptw.os,dl           is the page out of service?
1275           tnz       short_page_fault    process short pf
1276           canq      ptw.er,dl           is page in error from earlier read?
1277           tnz       page_read_error     yes, signal an error.
1278 
1279           lda       ast|aste.npfs_word,.aste see if no-page-fault-switch is on
1280           cana      aste.npfs,du        ..
1281           tnz       create_segment_fault
1282 
1283 
1284 "
1285 "         Here the commitment has been made to actually
1286 "         read in one page of virtual memory.
1287 "
1288 
1289           tsx       .ret,pc_trace$page_fault
1290 
1291 
1292           tsx       .ret,read_page
1293               tra   readin.goon         must wait for page
1294               tra   readin.goon
1295               tra   wait_any_event_apte wait for volmap event (in APTE by now)
1296 
1297 readin.goon:
1298           tsx       .ret,pc_trace$page_fault_end
1299           tsx       .ret,page_util_enter enter the page in the trace list
1300 "
1301 "         The following are various per-process meters about paging activity
1302 "         as well as some system meters about where page faults are
1303 "         happening.
1304 "
1305           lda       ast|aste.per_process_word,.aste count pdir faults
1306           cana      aste.per_process,du
1307           tze       *+2
1308           increment sst|sst.pdir_page_faults
1309 
1310           lxl       .tem,ast|aste.par_astep,.aste count faults in segs off dirs off root
1311           lxl       .tem,ast|aste.par_astep,.tem
1312           cmpx      .tem,sst|sst.root_astep+1
1313           tnz       *+2
1314           increment sst|sst.level_1_page_faults
1315 
1316           lda       ast|aste.dirsw_word,.aste     count dir pfts
1317           cana      aste.dirsw,dl
1318           tze       readin.meter_ndir_pft         meter in AST
1319           increment sst|sst.dir_page_faults
1320           tra       readin.meter_sgdir_join
1321 
1322 readin.meter_ndir_pft:                            "count in ASTE
1323           cana      aste.gtus,du                  " gtus in same word as dirsw
1324           tnz       readin.meter_sgdir_join       " if transparent, can't count faults
1325           lda       ast|seg_aste.usage,.aste
1326           adla      1,dl                          LOGICAL arith, please
1327           sta       ast|seg_aste.usage,.aste
1328 
1329 readin.meter_sgdir_join:
1330           lda       pds$page_fault_data+mc.scu.tpr.trr_word  count ring 0 page faults
1331           cana      scu.tpr.trr_mask,du
1332           tnz       *+2
1333           increment sst|sst.ring_0_page_faults
1334 
1335           aos       pds$page_waits      meter page waits
1336           aos       pds$number_of_pages_in_use
1337           ldq       sst|sst.nused       number of available pages
1338           eppbb     pds$apt_ptr,*       can also be used to reference tc_data
1339           epbpbp    bb|0                get pointer to base of apt
1340           lda       tc_data$n_eligible  make sure it isn't zero (can it ever be?)
1341           tze       no_eligible
1342           sta       temp
1343           div       temp                divide by the eligibility
1344           eaa       0                   clear a-reg
1345           staq      temp                save measurement
1346           cmpq      pds$number_of_pages_in_use  are we in equilibrium
1347           tmi       in_equilibrium      yes
1348           ldq       pds$number_of_pages_in_use  until then use this value
1349           staq      temp                save it as the measure
1350           asq       temp+1              which is doubled when not in equilibrium
1351 in_equilibrium:
1352           adaq      bp|cumulative_memory_usage
1353           staq      bp|cumulative_memory_usage
1354           ldaq      temp                reload measure for updating apte.paging_measure
1355           adaq      bb|apte.paging_measure add the paging measure
1356           staq      bb|apte.paging_measure and save it again
1357 
1358 no_eligible:
1359           ldx2      bb|apte.wct_index
1360           tze       skip_pinning        no WCTEs yet (initialization)
1361 "                                       bp -> to base of apt (set above)
1362           lxl       .tem,bp|wcte.pin_weight,2 get pin weight
1363           stx       .tem,cme_pin_counter,*.cme
1364 
1365 skip_pinning:
1366           epp       sst,sst$            restore sst ptr
1367 
1368           sxl       .cme,cmep           save cmep
1369           tsx       .ret,claim_mod_core write out mod pages
1370           lxl       .cme,cmep
1371           ldx       .ptw,ptp_astep      reload .ptw
1372           lxl       .aste,ptp_astep     and .aste
1373 
1374           eppbp     tc_data$            restore tcd ptr
1375           read_clock                    meter page fault time
1376           sbaq      pds$time_1          get cpu time for this fault
1377           adaq      bp|cpu_pf_time      keep sum of times
1378           staq      bp|cpu_pf_time
1379           aos       bp|cpu_pf_count     and count of faults
1380 
1381 "
1382 "
1383 "         Wait for the page fault as appropriate.
1384 "
1385           epp       ptw,sst|0,.ptw
1386 
1387 
1388 wait_ret:                     "here to wait for non/pd i/o
1389           lda       ptw|0               make this check just in case..
1390           cana      ptw.os,dl
1391           tze       quit
1392 
1393                                         "tra to pxss to wait for PTW I/O.
1394           ldq       cme.notify_requested,dl set flag for notify
1395           orsq      cme_flags,*.cme ..
1396           eaa       0,.ptw              create PTW event
1397 wait_page_fault_event:
1398           arl       18                  right justified
1399 wait_any_event:
1400           eppap     pds$apt_ptr,*       get apte ptr
1401           sta       ap|apte.wait_event  make it where can get notified.
1402 
1403 wait_any_event_apte:
1404           store_clock pds$time_1
1405           tsx       .ret,unlock_ptl     dump posting queue, possibly notifying
1406                                         "this event, and unlock ptl.
1407           meter_time pds$time_1,sst|sst.pf_unlock_ptl_time,sst|sst.pf_unlock_ptl_meterings
1408 
1409           tra       pxss$page_wait
1410 
1411 
1412 "^L
1413 "
1414 "         End of page fault processing here.
1415 "         These labels restart the page fault.
1416 "
1417 quit:     tsx       .ret,unlock_ptl     unlock page table lock
1418 
1419 wait_return:                            "return location from pxss$page_wait
1420           eppap     pds$page_fault_data get pointer to fault data
1421 
1422           read_clock
1423           cmpaq     pds$first_covert_event_time
1424           tpl       wait_return_no_delay
1425 
1426 " must wait until first_covert_event_time is met- that is, until covert channel
1427 " time is up
1428 
1429           ldaq      pds$first_covert_event_time
1430           staq      pds$arg_1
1431           tra       pxss$page_pause     " will return at wait_return
1432 
1433 wait_return_no_delay:
1434           inhibit   on
1435           ldaq      ap|mc.mask          retrieve previous mask
1436           oraq      channel_mask_set    turn on all channel mask
1437           anaq      scs$open_level      turn off unconfigured channel mask bits
1438           lxl1      prds$processor_tag
1439           lprpab    scs$mask_ptr,1
1440           xec       scs$set_mask,1
1441 
1442           ldaq      prds$+stack_header.stack_begin_ptr  restore stack end pointer for PRDS
1443           staq      prds$+stack_header.stack_end_ptr
1444 
1445           odd
1446           tsx       .ret,meter_virtual_time measure time to be taken out as virtual
1447 
1448 restart_fault:
1449           lpl       ap|mc.eis_info      restore EIS pointers and lengths
1450           lreg      ap|mc.regs
1451           lpri      pf_prs,*
1452           rcu       pf_scuinfo,*
1453           inhibit   off
1454 
1455 "^L
1456 
1457 "
1458 "         Error and unconventional cases in page fault processing.
1459 "
1460 fault_while_on_prds:
1461           lca       trbl_prds_pf,dl     flag for page fault on prds
1462           sta       scs$sys_trouble_pending
1463           lda       pds$processid       save our process ID
1464           stac      scs$trouble_processid  if we're the first
1465           lxl1      prds$processor_tag
1466           cioc      scs$cow_ptrs,1*     send connect to self
1467           nop
1468           nop
1469           nop
1470           tra       fault_while_on_prds
1471 "
1472 "         Come here when fault taken on page already being read.
1473 "
1474 
1475 short_page_fault:
1476 "         Compute cme addr so that wait_ret can turn on notify_requested.
1477 "
1478 
1479           increment sst|sst.short_pf_count        meter
1480 
1481           iftarget  l68       " Shift different on L68/ADP
1482              qrl    ptw_to_cmep.rl
1483           ifend
1484           iftarget  adp
1485              anq    ptw_add_mask,du     " Must mask off all but page number
1486              qls    ptw_to_cmep.ls
1487           ifend
1488 
1489           eax       .cme,sst|sst.cmp,*qu point to cme.
1490           tra       wait_ret            and wait for the page
1491 
1492 "
1493 "         Error bit set by done_ (done_read). Signal in
1494 "         faulting process.
1495 "
1496 page_read_error:
1497 
1498           tsx       .ret,disk_offlinep  is disk down as per pvt?
1499            tra      wait_any_event      yes, wait for it, event in A
1500 
1501           lca       ptw.er+1,dl         turn off error flag
1502           ansa      ptw|0               in PTW
1503 
1504           lda       PAGE_ERROR_IOERR,dl
1505           eppab     ast|0,.aste         ASTE
1506           tra       errquit
1507 
1508 bad_segno:
1509           lda       PAGE_ERROR_BADFAULT,dl
1510           eppab     null,*
1511           tra       errquit
1512 
1513 errquit:  sta       pc_err_type
1514           sprpab    pc_err_astep
1515           sprp      ptw,pc_err_ptwp
1516 
1517           tsx       .ret,unlock_ptl
1518 
1519 "
1520 "         Call pc_signal to copy machine conditions, and otherwise set
1521 "         up for the signaller
1522 
1523           ldaq      pc_signal_arglist
1524           staq      arg
1525           eppap     pc_err_type
1526           spriap    arg+2
1527           eppap     pc_err_astep
1528           spriap    arg+4
1529           eppap     pc_err_ptwp
1530           spriap    arg+6
1531           call      pc_signal$pc_signal(arg)
1532 
1533 "
1534 "         Now change the stack pointer so that if a process takes a page
1535 "         fault while signalling which also gets an error (RQO possibly)
1536 "         that we don't crash the system because our sp will still point
1537 "         to the PRDS.
1538 "
1539           ldaq      prds$+stack_header.stack_begin_ptr
1540           staq      prds$+stack_header.stack_end_ptr  reset stack end pointer
1541           eppap     pds$signal_data
1542           eppsp     ap|mc.prs+6*2,*     change sp to that at time of the fault
1543 
1544 "
1545 "         Now complete the virtual time calculation that were by-passed because we did
1546 "         not do an RCU.
1547 "
1548           tsx       .ret,meter_virtual_time
1549           tra       signaller$signaller now let the signaller do the work
1550 
1551 "         data for signal call.
1552 
1553 
1554 " ^L
1555 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1556 "
1557 "         pread
1558 "
1559 "         Entry to read a page into core.
1560 "
1561 "         Call is:
1562 "                   call page$pread(astep,pageno,waitev)
1563 "
1564 " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1565 
1566 pread:
1567           push
1568           stz       ap|6,*
1569           lda       read_entry,dl       set entry switch
1570           sta       entry_sw
1571           tsx       .2ret,init_savex    set up stack
1572 
1573 pread.loop:                             "may have paged in 2 or more stages, tho.
1574           eppap     sp|stack_frame.arg_ptr,*
1575           eppbp     ap|2,*
1576           epp       sst,sst$
1577           eppbp     bp|0,*
1578           eax       .aste,bp|0
1579           lda       ap|4,*
1580           eax       .ptw,bp|aste_size,al           point to ptw
1581           epp       ptw,sst|0,.ptw
1582 
1583           lda       ptw|0               is page in?
1584           cana      ptw.valid,dl
1585           tnz       return              yes, no problem.
1586 
1587           cana      ptw.er,dl           error from previous read?
1588           tze       pread.read_page     no, just read
1589 
1590           tsx       .ret,disk_offlinep
1591            tra      pread.wait_any      go wait global event if needed
1592 
1593 pread.read_page:
1594           tsx       .ret,read_page      do some work.
1595            tra      pread.wait          must wait, indicate or loop
1596            tra      pread.loop          must check again.
1597 
1598           eppap     pds$apt_ptr,*       retrieve wait event
1599           lda       ap|apte.wait_event
1600            tra      pread.wait_any      volmap event
1601 pread.wait:
1602 
1603 
1604 pread.wait_ret:
1605           arl       18                  convert to wait event
1606 pread.wait_any:
1607           eppap     sp|stack_frame.arg_ptr,* retrieve arg pointer
1608           sta       ap|6,*              return wait event
1609           tra       return
1610 "^L
1611 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1612 "
1613 "         pwrite
1614 "
1615 "         Entry to write a page out.
1616 "
1617 "         Call is:
1618 "                   call page$pwrite(astep,pageno)
1619 "
1620 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "  "
1621 
1622 pwrite:
1623           push
1624           lda       write_entry,dl      set up entry switch
1625           sta       entry_sw
1626           eppbp     ap|2,*              get pointer to APT
1627           eppbp     bp|0,*
1628           epbpbb    bp|0                let bb point to base of sst
1629           eax       .aste,bp|0
1630           lda       ap|4,*              get page number
1631           eax2      bp|aste_size,al
1632           eppbp     sst|0,.ptw          make sure bp points to PTW
1633           lda       ptw|0               pick up page table word
1634 
1635           iftarget  l68       " Shift different on L68/ADP
1636              arl    ptw_to_cmep.rl
1637           ifend
1638           iftarget  adp
1639              ana    ptw_add_mask,du     " Must mask off all but page number
1640              als    ptw_to_cmep.ls
1641           ifend
1642 
1643           eax       .cme,sst|sst.cmp,*au
1644           tsx       .2ret,init_savex    initialize save stack for x7
1645           tsx       .ret,write_page
1646 
1647 
1648           tra       return
1649 " ^L
1650 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1651 "
1652 "         pcleanup
1653 "
1654 "         Entry to get a page out of core.
1655 "
1656 "         Call is:
1657 "                   call page$pcleanup (astep, pageno)
1658 "
1659 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1660 
1661 pcleanup:
1662           push
1663           lda       cleanup_entry,dl
1664           sta       entry_sw
1665 
1666           tsx       .2ret,init_savex_bb
1667 
1668           epp       ptw,ap|2,*
1669           epp       ptw,ptw|0,*         get astep
1670           eax       .aste,ptw|0
1671           lda       ap|4,*              get pageno
1672           eax       .ptw,ptw|aste_size,al
1673           epp       ptw,sst|0,.ptw
1674 
1675           lda       ptw|0               get ptw
1676           cana      add_type.disk+ptw.os,dl
1677           tze       *+2
1678           tsx5      page_fault_error    "ERROR - PCLEANUP: CALLED ON BAD-STATE PAGE
1679 
1680           iftarget  l68       " Shift different on L68/ADP
1681              arl    ptw_to_cmep.rl
1682           ifend
1683           iftarget  adp
1684              ana    ptw_add_mask,du     " Must mask off all but page number
1685              als    ptw_to_cmep.ls
1686           ifend
1687 
1688           eax       .cme,sst|sst.cmp,*au
1689           arl       cmep_to_coreadd.rl
1690           sta       core_add
1691 
1692           lca       ptw.valid+1,dl
1693           ansa      ptw|0               turn off ptw access
1694 
1695           tsx       .2ret,check_accessible        " only CAM if needed
1696           tsx       .ret,cam_cache$cam_cache      make sure it takes
1697 
1698           tsx       .ret,cleanup_page   do the work.
1699           return
1700 "^L
1701 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
1702 "
1703 "         read_page, read_page_abs
1704 "
1705 "         Subroutine called by tsx7 to read a page into core (or if
1706 "         the page has never beeen referenced it will zero the core).
1707 "         A free block of core is found and possibly several 'writes' are
1708 "         queued in searching for the free core for the read_page entry.
1709 "         For the read_page_abs entry the free block of core
1710 "         specified by the caller is used.
1711 "
1712 "         tsx7      read_page
1713 "         <return with wait event in Areg>
1714 "         <return if page in memory>
1715 "         <return with volmap wait event set in APTE>
1716 "
1717 "         The subroutine expects
1718 "
1719 "                   x2 = pointer to PTW
1720 "                   x3 = pointer to AST entry
1721 "                   bp = pointer somewhere into SST
1722 "                   bb = pointer to base of SST
1723 "
1724 "         In addition, the read_page_abs entry expects
1725 "
1726 "                   x4 = pointer to core map entry of free block
1727 " " " " " " " " "" " " " " " " " " " " " " " " " " " " " " " " " "
1728 
1729 read_page_abs:
1730           tsx       .2ret,savex         recursive use of index 7
1731 
1732           tsx       .ret,check_allocation         make sure we have disk.
1733            tsx5     page_fault_error    "ERROR - OOPV ON EHS SEG"
1734            tra      read_page_abs.apte_event      volmap event
1735 
1736           tra       read_page_join
1737 
1738 read_page_abs.apte_event:
1739           eppap     pds$apt_ptr,*       event is in APTE
1740           lda       ap|apte.wait_event
1741           tra       unsavex_2           return to caller
1742 
1743 read_page:
1744           tsx       .2ret,savex         recursive use of index 7
1745 
1746           tsx       .ret,check_quota    check for quota overflow
1747           tsx       .ret,check_allocation is there disk available?
1748            tra      read_page.oodev     no disk on this PV
1749            tra      unsavex_2           must wait for volmap event
1750 
1751           stx       .ptw,ptp_astep      save x2 and x3 for now
1752           sxl       .aste,ptp_astep               ..
1753           tsx       .ret,find_core      find a free block of core
1754           ldx       .ptw,ptp_astep      restore x2 and x3
1755           eppbp     sst|0,.ptw          make sure bp points to PTW as well
1756           lxl       .aste,ptp_astep               ..
1757 "^L
1758 read_page_join:
1759 
1760 "         At this point, a cme to ptw binding is established.  To validate the
1761 "         assumptions of pc_recover_sst, it must be done in following order:
1762 "                   Auxiliary info into CME
1763 "                   cme.ptwp <= ptwp
1764 "                   ptw.add <= CORE
1765 
1766           lca          ptw.phm+ptw.phm1+ptw.er+1,dl  " turn off bad bits.
1767           ansa      ptw|0
1768           lda       ptw|0               copy device address to core map entry
1769           staddra   cme_devadd,*.cme store address from ptw into cme
1770           lca          cme.io+cme.phm_hedge+cme.removing+cme.notify_requested+1,dl
1771           ansa      cme_flags,*.cme clear random flags
1772 
1773           sxl       .aste,cme_astep,*.cme Associate astep with cme, not ptp yet.
1774 "         Do not store ptwp in cme until cme is ready, core clear, or ptw os.
1775 
1776 
1777           eaa       0,.cme              copy rel(cmep) to a-reg
1778           sbla      sst|sst.cmp+1       to get core address
1779           arl       cmep_to_coreadd.rl
1780           sta       core_add            save core address
1781 
1782           ldq       aste.init,du        turn off init bit in aste
1783           orsq      ast|aste.init_word,.aste      ..
1784           ersq      ast|aste.init_word,.aste      ..
1785           ldq       ast|aste.np_word,.aste increment number of pages in core
1786           anq       aste.np_mask,dl
1787           tnz       read.incr_np
1788 "
1789 " Reading in the first page causes dtu to advance.  Also, the dtm may be
1790 " advanced.  Lets see.
1791 "
1792           ldq       1,dl                this will advance to 1 page
1793           szn       pds$throttle_segment_state_changes
1794           tze       read.set_np         don't count events
1795           szn       entry_sw
1796           tnz       read.set_np         only count on fault side
1797 
1798 " Count this event.  Our assumptions:
1799 " dtm -   w access implies that we can (and must assume we will) advance dtm.
1800 "         Advancing dtm is always lower class visible since it propogates up
1801 "         the hierarchy.  However, we know that dirs advance dtm only when
1802 "         they want to (in sum$dirmod), so we don't count dirs as setting
1803 "         dtm here.
1804 "
1805 " dtu -   w access implies that our authorization equals the access class
1806 "         of the object, hence our setting dtu is not lower class visible.
1807 "         However, multi-class and directories violate this rule.
1808 "
1809 " Hence: a non-directory, multi-class writable object advances dtu and dtm
1810 " in a lower class visible way.  All other cases advance either dtu or dtm
1811 " but not both.
1812 
1813           lda       pf_sdw+1
1814           cana      sdw.write,du        check for write
1815           tze       read.covert_1       no write
1816           lda       ast|aste.dirsw_word,.aste " (also multi_class word)
1817           cana      aste.multi_class,du
1818           tze       read.covert_1       non-multi-class
1819           cana      aste.dirsw,dl
1820           tnz       read.covert_1       is a dir
1821 
1822           tsx       .ret,limit_covert_channel     both dtu and dtm set
1823 read.covert_1:
1824           tsx       .ret,limit_covert_channel     only dtu or dtm set
1825           ldq       1,dl                advance np to 1 page
1826           tra       read.set_np
1827 
1828 read.incr_np:
1829           adlq      1,dl
1830           erq       ast|aste.np_word,.aste
1831           anq       aste.np_mask,dl
1832 read.set_np:
1833           ersq      ast|aste.np_word,.aste
1834 
1835           lda       cme_devadd,*.cme  pick up cme devadd
1836           cana      add_type.non_null,dl is there an address?
1837           tnz       *+2                 must have real allocation here
1838           tsx5      page_fault_error    "ERROR - NO ALLOCATION IN PTW: READ_PAGE"
1839           als       0                   is it a real address?
1840           tpl       must_read           yes, actually read it
1841 
1842           "
1843           "Make zeroes for a predeposited address.
1844           "
1845           "tra      read.create_zeros   is right on the next page
1846 "^L
1847 "
1848 "         Page had either a null or nulled address in PTW.
1849 "         Create a fresh page of zeroes.
1850 "
1851 
1852 read.create_zeros:
1853           lda       ast|aste.records_word,.aste
1854           adla      =o001000,dl                   increment records used
1855           era       ast|aste.records_word,.aste
1856           ana       aste.records_mask_inner,dl
1857           ersa      ast|aste.records_word,.aste
1858 
1859 " Adding a page can be a covert event, if this is a multi-class object
1860 " (records used, etc. lower class visible) or if this is a dir without
1861 " terminal quota between it and the nearest upgraded node.
1862 " We don't have to worry about questions of setting csl/ru since the only
1863 " cases where page creations are covert events are cases where the page
1864 " creations are performed by trusted code themselves, and in which we know
1865 " that pages are created serially.  The user cannot create any random page
1866 " in these segments, only the next.  Thus, csl and ru contain the same
1867 " information, even though ru may later become less than csl if some of
1868 " these new pages end up zero.
1869 
1870           szn       pds$throttle_segment_state_changes
1871           tze       read.bump_quota     don't count events
1872           szn       entry_sw
1873           tnz       read.bump_quota     only on fault side
1874 
1875           lda       ast|aste.multi_class_word,.aste
1876           cana      aste.multi_class,du
1877           tze       read.create_check_dir
1878           tsx       .ret,limit_covert_channel     multi-class
1879           tra       read.bump_quota
1880 
1881 read.create_check_dir:
1882           cana      aste.dirsw,dl
1883           tze       read.bump_quota     non-dir
1884 
1885 " We have a dir.  We shall do a special bump quota which checks for
1886 " terminal-ness.
1887 
1888           tsx       .ret,bump_quota_covert_check increment used
1889           tsx       .ret,limit_covert_channel     upgraded found first
1890           tra       read.quota_bumped
1891 
1892 read.bump_quota:
1893           tsx       .ret,bump_quota     increment used
1894 read.quota_bumped:
1895           increment sst|sst.new_pages   meter new pages created
1896           tsx       .ret,clear_core     zero out the core
1897 "
1898 "         Now it is safe to store .ptw in cme
1899 "
1900           stx       .ptw,cme_ptwp,*.cme
1901           lda       core_add            pick up core address again
1902           als       coreadd_to_ptw.ls
1903           ora       add_type.core,dl
1904           staddra   ptw|0               store in ptw
1905 
1906           lda       ptw.phu+ptw.valid+df1,dl make used, accessible, refresh bit
1907           orsa      ptw|0
1908 
1909           stx       .aste,temp          calculate page number
1910           eax       .tem,1-aste_size,.ptw by subtracting astep from (ptwp-aste_size+1)
1911           sblx      .tem,temp
1912           stz       temp
1913           sxl       .tem,temp           save in temp
1914           lda       ast|aste.csl_word,.aste pick up current csl
1915           ana       aste.csl_mask_inner,du
1916           arl       aste.csl_shift
1917           cmpa      temp                compare ...
1918           tpl       unsavex_1           csl already larger than this
1919           ldq       temp                retrieve new csl value
1920           qls       aste.csl_shift      position for store into ASTE
1921           erq       ast|aste.csl_word,.aste
1922           anq       aste.csl_mask_inner,du
1923           ersq      ast|aste.csl_word,.aste
1924           tra       unsavex_1
1925 "^L
1926 " covert channel test - update covert channel event count, test bandwidth
1927 "
1928 limit_covert_channel:
1929           aos       pds$covert_event_count
1930           tmi       0,.ret              not enough events to monitor, yet
1931 
1932 " arriving here, we need to determine the bandwidth of these covert channel
1933 " events and possible audit or delay
1934 
1935           read_clock
1936           sbaq      pds$first_covert_event_time
1937           cmpaq     covert.big_time
1938           tpl       covert.reset_clock            time too great to count
1939           div       sst|sst.seg_state_change_limit usecs/bit in q
1940           stq       temp                          and temp
1941           mpy       sst|sst.audit_seg_state_change_bw
1942           cmpaq     covert.million
1943           tpl       covert.test_delay             usecs/bit*max_bps<1000000
1944 
1945 " audit here
1946 
1947           increment sst|sst.audit_seg_state_chg
1948           tsx       .2ret,page_error$excessive_seg_state_chg
1949 
1950 covert.test_delay:
1951           ldq       temp
1952           mpy       sst|sst.max_seg_state_change_bw
1953           cmpaq     covert.million
1954           tpl       covert.reset_clock            usecs/bit*max_bps<1000000
1955 
1956 " delay process
1957 
1958           increment sst|sst.delayed_seg_state_chg
1959 
1960           ldaq      covert.million
1961           div       sst|sst.max_seg_state_change_bw  desired usecs/bit
1962           sbq       temp                             delay as usecs/bit
1963           mpy       sst|sst.seg_state_change_limit   delay in aq
1964           staq      pds$first_covert_event_time      temp storage
1965           adlaq     sst|sst.seg_state_chg_delay   " this isn't really correct,
1966                                         " this is how long we want to delay,
1967                                         " not how long we will - but it's not
1968                                         " worth metering the real delay
1969           staq      sst|sst.seg_state_chg_delay
1970 
1971           read_clock                              set time to delay until
1972           adaq      pds$first_covert_event_time   see wait_return for use of time
1973           tra       covert.reset
1974 
1975 covert.reset_clock:
1976           read_clock
1977 covert.reset:
1978           staq      pds$first_covert_event_time
1979           lca       sst|sst.seg_state_change_limit
1980           sta       pds$covert_event_count
1981           tra       0,.ret
1982 
1983           even
1984 covert.big_time:
1985           oct       0,377777777777
1986 covert.million:
1987           dec       0,1000000
1988 "^L
1989 "
1990 "         Page had non-null add type. Must actually read page in.
1991 "         PTW is in A register.
1992 "
1993 
1994 must_read:
1995           sta       devadd              save device address in stack
1996 
1997 
1998           tsx       .ret,get_pvtx       get segment pvtx for fault
1999 
2000 read.must_rd.merge:
2001           tsx       .ret,device_control$check_ckdv  see if checking device incomplete
2002           tsx       .ret,store_pattern  if so, store pattern
2003 
2004 "
2005 "         Set up os bit before storing ptwp in cme, so page goes back in pc_r_sst.
2006 "
2007           lca       cme.io+1,dl         set io flag to "read"
2008           ansa      cme_flags,*.cme
2009 
2010           lda       ptw.os,dl           turn it on
2011           orsa      ptw|0
2012 
2013           stx       .ptw,cme_ptwp,*.cme
2014 
2015 
2016           lda       core_add            set up ptw afresh
2017           als       coreadd_to_ptw.ls
2018           ora       add_type.core,dl
2019           staddra   ptw|0               put in coreadd
2020 
2021           tsx       .ret,thread_out     OS out of list
2022 
2023           lda       int+pri,dl          (almost) always interrupt on reads
2024           sta       inter
2025           tsx       .ret,device_control$dev_read  read the page into core
2026           eaa       0,.ptw              ptw is he wait event
2027           tra       unsavex             wait this event
2028 "^L
2029 "
2030 "         Peculiar exits of read_page
2031 "
2032 
2033 read_page.oodev:                        "out of physical volume.
2034                                         "Signal a segfault.
2035           increment sst|sst.oopv        meter
2036 
2037           lda       aste.pack_ovfl,dl   turn on aste bit
2038           orsa      ast|aste.pack_ovfl_word,.aste in AST
2039 
2040           szn       entry_sw            better be a page_fault
2041           tze       *+2
2042           tsx5      page_fault_error    "ERROR - OOPV ON READ_PAGE CALL"
2043 create_segment_fault:
2044           eppap     pds$page_fault_data address mc
2045           lda       ap|mc.scu.apu_stat_word
2046           cana      scu.apu.dsptw,dl    is this ds fault?
2047           tze       *+2
2048           tsx5      page_fault_error    "ERROR - SETFAULT DESCRIPTOR SEGMENT"
2049 
2050           lxl       .tem,ap|mc.scu.cu_stat_word was it IF?
2051           canx      .tem,scu.cu.if,du
2052           tnz       *+2
2053           lda       ap|mc.scu.tpr.tsr_word get TSR if not IF
2054           als       1                   double segno
2055           ana       =o177776,du
2056 
2057           iftarget  l68       " On Level 68 only, must also set df_no to zero
2058             lcq     sdw.valid+sdw.df_no_mask+1,dl
2059           ifend
2060           iftarget  adp
2061             lcq     sdw.valid+1,dl
2062           ifend
2063 
2064           ansq      dseg$,au
2065           tsx       .ret,cam_cache$cam
2066           tra       quit                seg mover will handle
2067 
2068 "^L
2069 " " " " " " " " " " " " " " " " " " " " " " " " " " "
2070 "                                                   "
2071 "         disk_offlinep                             "
2072 "                                                   "
2073 "         Is the seg's disk offline?                "
2074 "                                                   "
2075 "         tsx       .ret,disk_offlinep              "
2076 "          tra      yes, event in A                 "
2077 "         null      no                              "
2078 "                                                   "
2079 " " " " " " " " " " " " " " " " " " " " " " " " " " "
2080 
2081 disk_offlinep:
2082           tsx       .2ret,savex
2083           tsx       .ret,get_pvtx
2084           tsx       .ret,device_control$disk_offlinep
2085            tra      *+2                 offline
2086           tra       unsavex_1           not offline
2087 
2088           lca       ptw.er+1,dl         turn OFF the error bit. This is
2089           ansa      ptw|0               so that when the guy tries again
2090                                         "when the disk finally comes back,
2091                                         "the next call to disk_offlinep
2092                                         "doesnt cause a signal.
2093           lda       disk_offline_event
2094           tra       unsavex
2095 
2096 disk_offline_event:
2097           aci       "dskw"
2098 "^L
2099 "
2100 "         Check to see if page has allocation. Give one
2101 "         if needed.
2102 "
2103 "         tsx7      check_allocation
2104 "         <return in out of room on physical volume>
2105 "         <return if must wait volmap event, event set in APTE>
2106 "         <return if page has allocation>
2107 
2108 check_allocation:
2109           lda       ptw|0               grab ptw
2110           cana      add_type.core,dl
2111           tze       *+2                 make sure we're doing this right
2112           tsx5      page_fault_error    "ERROR - CORE ADDR IN PTW: READ_PAGE"
2113           cana         add_type.disk,dl    " real devadd?
2114           tnz       2,.ret              yes, that's fine.
2115 
2116           stx       .aste,pageno        ASTE offset
2117           eax       .tem,-aste_size,.ptw
2118           sblx      .tem,pageno         Page number
2119           eaq       0,.tem
2120           qrl       18
2121           stq       pageno
2122           ldq       ast|aste.vtocx,.aste
2123           anq       -1,dl               VTOCE Index
2124           stq       vtocx
2125 
2126           tsx       .2ret,savex         enter free_store
2127           tsx       .ret,get_pvtx       get pvtx
2128           tsx       .ret,free_store$withdraw  get an address
2129            tra      unsavex             OOPV
2130            tra      unsavex_1           volmap wait event
2131 
2132 "
2133 "         Put nulled address where null one was. With respect to pc_recover_sst,
2134 "         this is all the same.
2135 "
2136           lda       devadd
2137           ora       ptw.nulled,du       this is semikilled address
2138           sta       devadd
2139 
2140           staddra   ptw|0               put in new address
2141 unsavex_2:
2142           ldx       .ret,stackp,di
2143           tra       2,.ret              return
2144 "^L
2145 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
2146 "
2147 "         find_core_
2148 "
2149 "         Subroutine to find a block of free core.
2150 "
2151 "         Call is:
2152 "                   tsx7 page_fault$find_core_
2153 "
2154 "                   tsx7 find_core
2155 "
2156 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
2157 
2158           equ       pre_seek_limit,15   " Mod failure detection
2159 
2160 find_core_:                             " Externally available to ALM PC
2161 
2162 find_core:
2163           tsx       .2ret,savex         save index 7
2164           increment sst|sst.needc       meter times core was needed
2165           lca       1,du                init ctr for out-of-core to -2**18
2166           sta       total_steps
2167 fploop:
2168           stz       count               zero count of steps
2169           lca       pre_seek_limit,dl   initialize mod failure ctr
2170           sta       temp1
2171           ldx       .cme,sst|sst.usedp  set cmep
2172 
2173 "     re-entry from find_core.ptw_ng and find_core.skip_meter_mod
2174 
2175 fc1:
2176           lda       cme_flags,*.cme     check for total acceptability
2177           cana      cme.removing+cme.abs_w,dl
2178           tnz       find_core.cme_ng    something unusable- meter & skip
2179 
2180           ldx       .ptw,cme_ptwp,*.cme Is core free? Set ptp.
2181           tze       found_core          yes, take it.
2182           epp       ptw,sst|0,.ptw      point at ptw
2183           lda       ptw|0               let's examine the ptw...
2184 
2185           cana      ptw.phu+ptw.wired+ptw.os+ptw.phm+ptw.phm1,dl      " make quick check
2186           tnz       find_core.ptw_ng    something in ptw is unacceptable.
2187 
2188           ldx       .tem,cme_pin_counter,*.cme
2189           tpnz      find_core.skip_pinned  do not evict if still pinned
2190 
2191 "
2192 "         Now attempt to evict the page.
2193 "
2194 "^L
2195 "
2196 "         Here is where access is taken off for a potential eviction.
2197 "         If we lose timing window, access comes back.  Note that core address
2198 "         in PTW stays valid until cleanup_page has run, and contents of
2199 "         core page can be ignored (we are sure page is pure).
2200 
2201           lca       ptw.valid+1,dl      set directed fault 1 in ptw
2202           ansa      ptw|0               ..
2203           lda       ptw|0               make sure coreadd gets set
2204           ana       ptw_add_mask,du     " Mask off all but the page address bits
2205           arl       ptw_to_coreadd.rl   " Clear the right place in the cache
2206           sta       core_add            ..
2207 
2208           lxl       .aste,cme_astep,*.cme " get astep
2209           tsx       .2ret,check_accessible        " CAM if needed
2210           tsx       .ret,cam_cache$cam_cache " make sure the access gets turned off
2211 
2212           lda       ptw|0               retrieve ptw for modified bit test
2213           cana      ptw.phm+ptw.phm1+ptw.wired,dl has the page been modified now? or wired?
2214           tnz       restore_ptw_access  appear to have lost race
2215 
2216           stx       .cme,sst|sst.usedp  this frame now LRU
2217           tsx       .ret,cleanup_page   evict the page
2218 
2219 found_core:
2220           increment sst|sst.steps       meter
2221           ldx       .tem,cme_fp,*.cme move to MRU
2222           stx       .tem,sst|sst.usedp
2223           tra       unsavex             find_core returns
2224 "^L
2225 "
2226 "         PTW has some kind of unacceptable state: possibilities:
2227 "
2228 "   1.    out of service-               illegal- crash system
2229 "   2.    wired-                        skip and meter
2230 "   3.    modified-                     leave alone for claim_m_c to evict/unuse.
2231 "   4.    nypd-                         leave alone for c_m_c to write to pd if unused.
2232 "   5.    used-                         "unuse" for replacement algorithm.
2233 
2234 find_core.ptw_ng:
2235           cana      ptw.os,dl           this ought not be..
2236           tze       *+2
2237           tsx5      page_fault_error    "ERROR - FINDCORE FINDS OS ON LIST
2238 
2239           cana      ptw.phm+ptw.phm1,dl has it been modified?
2240           tnz       find_core.skip_meter_mod must be written, can't take.
2241                                         "don't care whether used or not -must leave
2242                                         "both bits for c_m_c, who will off them.
2243 
2244           cana      ptw.wired,dl        is it wired?
2245           tnz       find_core.skip_wired
2246 "
2247 "         Must be used, skip and meter, impl. replacement algorithm
2248 "         by turning bit off.
2249 "
2250           increment sst|sst.skipu       count used.
2251           lca       ptw.phu+1,dl        turn off phu bit in PTW
2252           ansa      ptw|0
2253           lda       ptw.phu1,dl         turn PHU1 ON in PTW
2254           orsa      ptw|0
2255 
2256 skip:
2257           ldx       .cme,cme_fp,*.cme   go to next core map entry in list
2258           increment sst|sst.steps       count step
2259           aos       total_steps         up count of steps taken looking for core
2260           tmi       fc1                 if still neg, loop on.
2261           tra       page_error$out_of_core Multics not in operation.
2262 
2263 
2264 restore_ptw_access:                     "come here when 2nd cpu mod in window
2265           lda       ptw.valid,dl                  remove directed fault from ptw
2266           orsa      ptw|0               ..
2267 find_core.skip_meter_mod:
2268           increment sst|sst.skipm       count skip mod
2269 cmod1:    increment sst|sst.steps
2270           ldx       .tem,cme_fp,*.cme   pt at next cme
2271           cmpx      .tem,sst|sst.usedp  have we walked whole queue?
2272           tze       mods_excessive      will run claim_mod_core on whole mem
2273           eax       .cme,0,.tem         go to next cme
2274           aos       temp1               see if too many skipmods
2275           tpl       mods_excessive      too many
2276           tra       fc1
2277 
2278 find_core.skip_pinned:
2279           increment sst|sst.fc_skips_pinned  no. of pin skips in find_core
2280           ldx       .tem,cme_pin_counter,*.cme
2281           sblx      .tem,1,du
2282           tmi       skip                never happen
2283           stx       .tem,cme_pin_counter,*.cme
2284           tra       skip
2285 
2286 
2287 "^L
2288 "
2289 "         cme is unacceptable- following may be the case:
2290 "
2291 "   1.    removing            can't page in, must not be used. skip.
2292 "   2.    abs_w               IN PROCESS of being abs-wired.. may not
2293 "                             page in evict_page will do it by special means,
2294 "                             must avoid getting vol map in here by accident.
2295 
2296 find_core.cme_ng:
2297 
2298           cana      cme.abs_w,dl        abs wiring?
2299           tze       skip                no, just skip.
2300 
2301 find_core.skip_wired:
2302           increment sst|sst.skipw
2303           tra       skip                ..
2304 
2305 "
2306 "         We arrive here when an excess of skips-mod have been made.
2307 "         Potentially, every page in core can be mod and used. Hence,
2308 "         tentatively, the fast find_core has failed. Do it the old way.
2309 "
2310 mods_excessive:
2311           stx       .cme,sst|sst.usedp save ptr to NEXT cme
2312           increment sst|sst.pre_seeks_failed      meter
2313           tsx       .ret,claim_mod_core do writes, may even post.
2314           tra       fploop              restart find_core_
2315 
2316 "^L
2317 """"""""""""""""""""""""""""""""""""""""""""""""""
2318 "                                                 "
2319 "         Subroutine to evict one                 "
2320 "         page from core.                         "
2321 "                                                 "
2322 """"""""""""""""""""""""""""""""""""""""""""""""""
2323 
2324 cleanup_page:
2325           tsx       .2ret,savex
2326           lxl       .aste,cme_astep,*.cme get astep
2327 
2328 "
2329 "         Unbind core from ptw here. For validity of pc_recover_sst, this
2330 "         must be done in the following order:
2331 "                   Put non-core address back in ptw
2332 "                   cme.ptwp <= 000000
2333 "                   Clean up cme
2334 "
2335           lda       cme_devadd,*.cme clear out ptw
2336           staddra   ptw|0
2337 
2338           lda       ast|aste.np_word,.aste subtract from count of pages in core
2339           sbla      1,dl
2340           era       ast|aste.np_word,.aste
2341           ana       aste.np_mask,dl
2342           ersa      ast|aste.np_word,.aste
2343           lda       ast|aste.np_word,.aste
2344           cana      aste.np_mask,dl     see if any pages left in core
2345           tnz       cleanup.np_nonzero  yes, continue
2346 
2347           lda       aste.init,du        no, turn init bit ON in ASTE
2348           ora       ast|aste.init_word,.aste      ..
2349           sta       ast|aste.init_word,.aste  gtus is in same word, so...
2350           cana      aste.gtus,du        check gtus. If on, leave dtu alone
2351           tnz       cleanup.np_nonzero  nothing to do
2352 
2353           read_clock                    get time
2354           lls       20                  convert to fstime in A
2355           sta       ast|aste.dtu,.aste  and drop it in
2356 
2357 cleanup.np_nonzero:
2358           tsx       .ret,check_synch_cleanup do housekeeping for synchronized page
2359           lda       ptw|0               if not live address, must adjust quota...
2360           cana      add_type.non_null,dl and records_used.
2361           tze       cleanup.rsq         null, reset recs.
2362           cana      ptw.nulled,du       is it nulled?
2363           tze       cleanup.nrsq1       not nulled, don't reset.
2364 cleanup.rsq:
2365           tsx       .ret,update_csl     make sure csl is correct
2366           lda       ast|aste.records_word,.aste
2367           ana       aste.records_mask_inner,dl
2368           sbla      =o001000,dl         decrement records used
2369           tpl       cleanup.recused_okay
2370           szn       pvt$esd_state
2371           tnz       cleanup.recused_okay
2372           tsx5      page_fault_error    "ERROR - RECUSED WENT NEG: CLEANUP"
2373 cleanup.recused_okay:
2374           era       ast|aste.records_word,.aste
2375           ana       aste.records_mask_inner,dl
2376           ersa      ast|aste.records_word,.aste
2377           tsx       .ret,reset_quota    deduct a quotum used
2378 cleanup.nrsq1:
2379           eax       .tem,0              zero ptw correspondence
2380           stx       .tem,cme_ptwp,*.cme ..
2381           sxl       .tem,cme_astep,*.cme zero astep correspondence too
2382           tsx       .ret,thread_to_lru  move to head of list
2383           lca       ptw.phm+ptw.phm1+1,dl         " turn off mod
2384           ansa      ptw|0
2385           tra       unsavex
2386 "^L
2387 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
2388 "                                                           "
2389 "                                                           "
2390 "         claim_mod_core                                    "
2391 "                                                           "
2392 "         Tsx       .ret,claim_mod_core to sweep            "
2393 "                             up all the writes that        "
2394 "                             find_core chose not to do.    "
2395 "                                                           "
2396 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
2397 
2398 claim_mod_core:
2399           tsx       .2ret,savex         save return
2400           increment sst|sst.write_hunts meter
2401 
2402 mc_continue:
2403           ldx       .cme,sst|sst.wusedp start at last point
2404 
2405 mclp:     cmpx      .cme,sst|sst.usedp  are we up to find_core?
2406           tze       cl_done
2407           increment sst|sst.claim_steps meter steps
2408 
2409           lda       cme_flags,*.cme look at cme
2410           cana      cme.removing+cme.abs_w,dl        " check unacceptable states
2411           tnz       cl_bad
2412 
2413           ldx       .ptw,cme_ptwp,*.cme point to ptw
2414           tze       cl_free             this is really bad, for
2415                                         "this cme should be
2416                                         "in front of usedp.
2417           epp       ptw,sst|0,.ptw      point to ptw
2418 
2419           lda       ptw|0               consider ptw
2420           cana      ptw.os+ptw.wired,dl
2421           tnz       cl_ptwbad
2422           cana      ptw.phm+ptw.phm1,dl           " we only care about those f_c_ skipped
2423           tze       cl_notmod
2424 
2425           cana      ptw.phu,dl          see if used
2426           tnz       cl_used             turn off used if on
2427 
2428           ldx       .tem,cme_pin_counter,*.cme see if page is pinned
2429           tpnz      cl_pinned
2430 
2431           increment sst|sst.claim_writes meters
2432           ldx       .tem,cme_fp,*.cme peek ahead to next cme
2433           stx       .tem,sst|sst.wusedp save pointer
2434 
2435           lxl       .aste,cme_astep,*.cme pick up astep
2436           tsx       .ret,write_page     write_page will do all necessary
2437           tra       mc_continue
2438 
2439 mc_end:   ldx       .cme,cme_fp,*.cme scan on into map
2440           tra       mclp
2441 
2442 cl_bad:
2443           increment sst|sst.claim_skip_cme        A CME had permanent unacceptable state, or RWS
2444           tra       mc_end
2445 
2446 cl_ptwbad:
2447           increment sst|sst.claim_skip_ptw        PTW wired
2448           tra       mc_end
2449 
2450 cl_free:
2451           increment sst|sst.claim_skip_free       A CME was free to claim_mod_core
2452           tra       mc_end
2453 
2454 cl_notmod:
2455           increment sst|sst.claim_notmod          not modified, not interesting
2456           tra       mc_end
2457 
2458 cl_used:
2459           lcq       ptw.phu+1,dl                  mod, but used.
2460           ansq      ptw|0                         turn off used and pray for cam.
2461           ldq       ptw.phu1,dl                   dont screw up working sets
2462           orsq      ptw|0
2463           increment sst|sst.claim_passed_used
2464           tra       mc_end
2465 
2466 cl_pinned:
2467           increment sst|sst.cl_skips_pinned  no. of pin skips in claim_mod
2468 "                                       cme_pin_counter in x0
2469           sblx      .tem,1,du
2470           tmi       mc_end              never happen
2471           stx       .tem,cme_pin_counter,*.cme
2472           tra       mc_end
2473 
2474 cl_done:
2475           stx       .cme,sst|sst.wusedp
2476           tra       unsavex
2477 "^L
2478 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
2479 "
2480 "         write_page
2481 "
2482 "         Subroutine to check to see a page should be written out.
2483 "         If so, initiate the I/O.
2484 "
2485 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
2486 
2487 write_page:
2488 "
2489 "         Page has been modified
2490 "
2491           tsx       .2ret,savex         recursive use of .ret
2492           tsx       .ret,get_pvtx       get pvtx from AST
2493           tsx       .ret,pc_trace$write_page
2494           eaa       0,.cme              compute core_add from cmep
2495           sbla      sst|sst.cmp+1
2496           arl       cmep_to_coreadd.rl  ..
2497           sta       core_add
2498           lda       cme_devadd,*.cme save devadd in stack
2499           sta       devadd              ..
2500 
2501           lda       ptw|0               inspect ptw
2502           cana      ptw.os,dl           check for o/s
2503           tze       *+2
2504           tsx5      page_fault_error    "ERROR - WRITE CALL ON OS PAGE"
2505           cana      ptw.phm+ptw.phm1,dl           " if neither on, obsolete call
2506           tze       unsavex
2507 
2508 
2509           lxl       .tem,ast|aste.par_astep,.aste dont update if no parent
2510           tze       write.dont_set_fms
2511 
2512           ldq       ast|aste.gtms_word,.aste      check global-transparent-modified-switch
2513           canq      aste.gtms,du
2514           tnz       write.dont_set_fms  if on, don't set fms
2515 
2516           cana      ptw.phm,dl          was fms set by pc$update_incore_fms?
2517           tze       write.dont_set_fms  yes, don't set it
2518 
2519           eax       .tem,0,.aste        copy AST parent to x0 (first time is AST)
2520           read_clock                    get current time
2521           lrs       16                  convert to fstime in Q
2522           lda       aste.fms,du         get set to turn on all superior fms's
2523 
2524 write.set_parent_fms:
2525           orsa      ast|aste.fms_word,.tem
2526           stq       ast|aste.dtm,.tem   set dtm as well
2527           lxl       .tem,ast|aste.par_astep,.tem
2528           tnz       write.set_parent_fms
2529 
2530 write.dont_set_fms:
2531           tsx       .2ret,set_up_abs_seg abs_seg1 -> page in memory, ap -> abs_seg1
2532           tsx       .ret,check_for_synch_hold synchronized page, not to be written
2533           tra       unsavex             yes - don't write
2534 
2535           szn       tc_data$system_shutdown  don't null pages during shutdown
2536           tnz       page_non_zero       yes, pretend page non-zero(don't deposit anything)
2537           ldq       ast|aste.dnzp_word,.aste don't null if special flag set
2538           canq      aste.dnzp,du        ..
2539           tnz       page_non_zero
2540 
2541           lda       ptw|0               Don't null wired pages.
2542           cana      ptw.wired,dl
2543           tnz       page_non_zero
2544 
2545           tsx       .ret,check_for_zero test for a zero page
2546           tra       page_non_zero       return here if really not zero
2547           lca       ptw.valid+1,dl      set directed fault 1 in ptw
2548           ansa      ptw|0               ..
2549 
2550           tsx       .2ret,check_accessible        " only CAM if needed
2551           tsx       .ret,cam_cache$cam_cache make sure people see it
2552 
2553           tsx       .ret,check_for_zero try again after turning off access
2554           tra       page_non_zero_a     he just modified it before we zapped access, phooey
2555 "
2556 "         page was all zeroes
2557 "
2558           increment sst|sst.zero_pages
2559           tsx       .ret,pc_trace$zero_page
2560 
2561 
2562           lda       ptw.nulled,du       null the disk addr in cme.
2563           orsa      cme_devadd,*.cme
2564 
2565           lda       aste.fmchanged,du   turn on map changed bit
2566           orsa      ast|aste.fmchanged_word,.aste
2567           tsx       .ret,cleanup_page   evict page from core, turns off phm.
2568           tra       unsavex
2569 " ^L
2570 "         come here because the page is non-zero and must be written out
2571 "
2572 
2573 page_non_zero_a:
2574           lda       ptw.valid,dl                  remove directed fault from ptw
2575           orsa      ptw|0               ..
2576 page_non_zero:
2577           lda       cme_devadd,*.cme
2578           cana      add_type.non_null,dl is it real null?
2579           tnz       write.pnz.to_disk
2580 
2581 "
2582 "         Was a real null address- this must not be so at this point!!!
2583 "
2584 write.nz.was_real_null:
2585 "
2586           tsx5      page_fault_error    "ERROR - NO ALLOCATION AT WRITE TIME"
2587 
2588 
2589 
2590 write.pnz.to_disk:
2591           lda       unnull_mask         unnull, but not in core map
2592           ansa      devadd
2593 
2594 "^L
2595 "
2596 "         Actually set up like we're gonna write.
2597 "         Recovery strategy requires cme.io set before os set.
2598 "
2599 
2600 do_write:
2601           tsx       .ret,thread_out     OS out of list
2602 
2603           lda       cme.io,dl           turn on write bit in CME
2604           orsa      cme_flags,*.cme ..
2605 
2606           lda       ptw.os,dl           set ptw out of service
2607           orsa      ptw|0
2608 
2609           lca       ptw.phm+ptw.phm1+1,dl turn it off once ptw.os is on.
2610           ansa      ptw|0
2611 
2612           tsx       .2ret,check_accessible        " if needed:
2613           tsx       .ret,cam_cache$cam_ptws       turn it off on all cpus.
2614 
2615 do_write.not_mod:
2616           stz       inter               generally don't interrupt on writes
2617           lda       entry_sw            see if write entry
2618           cmpa      write_entry,dl
2619           tnz       do_write.not_pri    not, continue
2620 
2621           lda       int+pri,dl          interrupt on write entry
2622           sta       inter
2623 do_write.not_pri:
2624           tsx       .ret,device_control$dev_write  initiate the write
2625           tra       unsavex
2626 
2627 "^L
2628 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
2629 "
2630 "         done,done_
2631 "
2632 "         Entry (subroutine) to post the completion of I/O.
2633 "         Call is
2634 "                   call done(core_add,errcode)
2635 "         or
2636 "                   tsx7 done_
2637 "
2638 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
2639 
2640 done:
2641           tra       core_queue_man$disk_post
2642 
2643 
2644 done_:
2645           eppbb     sst$                bb must point into SST for PAGE
2646           tsx       .2ret,savex         save return loc in stack
2647           lda       core_add            get core map entry pointer
2648           als       coreadd_to_cmep.ls
2649           eax       .cme,sst|sst.cmp,*au  set up .cme
2650 
2651           tsx       .ret,pc_trace$done
2652 "
2653 "         Flags to A-reg until we know where we're headed.
2654 "
2655           lxl       .tem,cme_astep,*.cme save astep for later
2656           stx       .tem,done_astep
2657 
2658           lda       cme_flags,*.cme see if a read/write sequence is active
2659 
2660           ldq       cme_devadd,*.cme pick up device address out of CM entry
2661           stq       devadd              and save in stack
2662 
2663           ldx       .ptw,cme_ptwp,*.cme get ptp
2664           tze       page_error$error_in_done  core must be used
2665           eppbp     sst|0,.ptw
2666           lxl       .tem,ptw|0          check for out of service
2667           canx      .tem,ptw.os,du
2668           tze       page_error$error_in_done
2669           lxl       .aste,cme_astep,*.cme get astep
2670 
2671           cana      cme.io,dl           Was this a write?
2672           tnz       done_write          yes, go handle it
2673           "tra      done_read           *** is on the next page ***
2674 "^L
2675 "         done_read -- thread core in mru,
2676 "                      and turn on PTW access.
2677 "
2678 
2679 done_read:
2680           tsx       .ret,thread_in_mru  make most recently used
2681 
2682           szn       errcode             check error code
2683           tnz       error_on_read       error ...
2684 "
2685 "         Check for device incomplete
2686 "
2687           tsx       .ret,device_control$check_ckdv
2688            tsx      .ret,check_pattern  dvctl returns here if checking on
2689             tra     done.read.no_ckdv_error c_p comes here if no error.
2690                                            "also, dvctl comes here if not checking!
2691           tsx       .2ret,page_error$device_error
2692           tra       error_on_read       treat as fatal error
2693 
2694 done.read.no_ckdv_error:
2695           lda       ptw.valid+df1,dl    turn on access
2696           orsa      ptw|0
2697           lca       ptw.os+1,dl         turn off os bit
2698           ansa      ptw|0
2699 
2700 "         tra       notify_code         " (Actually, just fall through to this)
2701 "
2702 "
2703 
2704 "
2705 "^L
2706 "         Post a read or write complete, with or without error.
2707 "         Call handler for I/O to volmap_seg.
2708 "         Cause a page faulter to restart his fault, and cause
2709 "         call side to retry.
2710 "
2711 notify_code:
2712 "
2713 "         Check for notify_requested. If none, neither notify
2714 "         nor idle pre_empt.
2715 "
2716           lda       cme.notify_requested,dl       get flag
2717           cana      cme_flags,*.cme     see if on in cme
2718           tze       notify_end          no, just return
2719           ersa      cme_flags,*.cme     was on. Turn off and
2720                                         "notify/preempt.
2721 done.notify.uncond:
2722           szn       tc_data$pre_empt_flag  see if we're pre-empting (and notifying)
2723           tnz       check_idle          we're not pre-empting. are we an idle process ?
2724           eaq       0,.ptw              get event from ptw addr
2725           qrl       18
2726           stq       pds$arg_1           save argument
2727           tra       pxss$page_notify
2728 
2729           entry     notify_return
2730 notify_return:
2731           epp       sst,sst$            restore sst pr, possibly for done_ entry.
2732 notify_end:
2733           ldx       .tem,done_astep     astep
2734           lda       sst|aste.volmap_seg_word,.tem see if this is a volmap_seg
2735           cana      aste.volmap_seg,dl
2736           tze       unsavex             no - return to the caller of done
2737           lda       sst|aste.pvtx_word,.tem
2738           arl       aste.pvtx_shift
2739           ana       aste.pvtx_mask,dl   pvtx in Areg
2740           tsx       .ret,volmap_page$post_io      do asynchronous stuff
2741           epp       sst,sst$            restore
2742           tra       unsavex             return to caller of done
2743 
2744 check_idle:
2745           ldaq      pds$apt_ptr         see if we're an idle process
2746           cmpaq     prds$idle_ptr
2747           tnz       notify_end          no, just return
2748           lda       apte.pre_empt_pending,du
2749           eppbp     pds$apt_ptr,*
2750           orsa      bp|apte.flags
2751           lxl1      prds$processor_tag
2752           stc2      pds$connect_pending
2753           cioc      scs$cow_ptrs,1*
2754           tra       notify_end
2755 "^L
2756 "
2757 "         error_on_read - put Pdisk address back in PTW
2758 "
2759 
2760 error_on_read:
2761           increment sst|sst.page_read_errors      meter
2762           tsx       .ret,cleanup_page   out of core
2763 
2764           lca       ptw.os+1,dl         Now oocore, off os.
2765           ansa      ptw|0
2766 
2767           lda       ptw.er,dl           mark ptw as signalable
2768           orsa      ptw|0
2769           tsx       .ret,get_pvtx
2770           tsx       .ret,call_disk_emergency
2771           tra       done.notify.uncond
2772 "^L
2773 "
2774 "         done_write - remove O/S status,
2775 "                      and thread core in LRU.
2776 "
2777 
2778 done_write:
2779 
2780           lca       1,dl                decrement global count of writes.
2781           asa       sst|sst.wtct
2782           tpl       *+2
2783           stz       sst|sst.wtct        make sure stays +.
2784 
2785           lda       ptw.phm+ptw.phu,dl  count uses of pages being written
2786           cana      ptw|0               ..
2787           tze       *+2                 not used, don't count
2788           increment sst|sst.mod_during_write
2789           lca       ptw.os+ptw.er+1,dl  turn off OS and ERR flags.
2790           ansa      ptw|0
2791           lda       ptw.valid,dl        turn access on - it's off for synch pages
2792           orsa      ptw|0
2793 
2794           ldq       errcode             if error, go process it, passing
2795           tnz       error_on_write      error code in Q.
2796 
2797           lca       cme.phm_hedge+1,dl turn off write
2798           ansa      cme_flags,*.cme scheduler and pd_upflag
2799 
2800 "
2801 resurgo:
2802           lda       cme_devadd,*.cme
2803           cana      ptw.nulled,du       is this null?
2804           tze       rethread            no, ordinary write.
2805           era       ptw.nulled,du
2806           sta       cme_devadd,*.cme
2807           increment sst|sst.resurrections         meter
2808 resurgo.fmchanged:
2809           lda       aste.fmchanged,du   turn on fmc bit
2810           orsa      ast|aste.fmchanged_word,.aste
2811 no_dblw:
2812 rethread:
2813           tsx       .ret,thread_in      insert in core map at lru
2814           tra       notify_code         and notify waiting processes
2815 "^L
2816 "
2817 "         error_on_write - Zero data if data error,
2818 "                          but leave in core as modified if device inop.
2819 "
2820 
2821 error_on_write:     "errcode passed in Q.
2822           increment sst|sst.page_write_errors meter
2823 
2824           canq      errflags.memory_unusable,dl   page damage or mem problem
2825           tnz       done.werr.deverr
2826 
2827 
2828 "                             not pd case- analyze errcode
2829           canq      errflags.device_inoperative,dl          disk down?
2830           tnz       write_device_inop   yes, handle it
2831 
2832 "
2833 "         Must be data error on write
2834 done.werr.deverr:
2835 "
2836           lda       aste.damaged,dl
2837           orsa      ast|aste.damaged_word,.aste
2838           lda       aste.fmchanged,du   cause vtoce update
2839           orsa      ast|aste.fmchanged_word,.aste
2840 
2841           tsx       .ret,thread_in      get core in list
2842           lca       ptw.valid+1,dl      turn off access
2843           ansa      ptw|0
2844           tsx       .ret,cam_cache$cam_cache
2845           tsx       .ret,cleanup_page   drive guy out of core
2846 
2847           lda       ptw.er,dl
2848           orsa      ptw|0
2849 "
2850 "         Try for an older copy of the page in any case.
2851 "
2852           eax       .ret,page_error$reverting_page assume some stuff out there
2853           lda       cme_devadd,*.cme get diskaddr or pdaddr
2854           cana      add_type.non_null,dl any good stuff atall?
2855           tnz       done.werr.deverr.printerr ptw ok
2856 
2857           eax       .ret,page_error$zeroing_page
2858           ldq       errcode             see what case
2859           lda       page_bad_null,du    assume device lossage
2860           canq      errflags.memory_unusable,dl
2861           tze       *+2
2862           lda       page_devparity_null,du parity case
2863           staddra   ptw|0               in the ptw
2864 done.werr.deverr.printerr:
2865           tsx       .ret,0,.ret         print barfage
2866           lda       errcode             do we have to make main mem vanish?
2867           cana      errflags.memory_unusable,dl
2868           tze       done.notify.uncond  exit
2869 
2870           tsx       .ret,delete_mm_frame delete this frame of main mem
2871           tra       done.notify.uncond
2872                     "cme has been freed, don't know whether
2873                     "to notify or not, so do it.
2874 
2875 write_device_inop:
2876           tsx       .ret,get_pvtx
2877           tsx       .ret,call_disk_emergency
2878 
2879           lda       ptw.phm1,dl         turn mod bit back on
2880           orsa      ptw|0
2881 
2882 finish_write_error:
2883           tsx       .ret,thread_in_mru avoid repl algorithm
2884           tra       notify_code
2885 
2886 
2887 
2888 "^L
2889 "
2890 "         Clear out and deconfigure main memory frame.
2891 "
2892 delete_mm_frame:
2893           tsx       .2ret,savex
2894           tsx       .ret,thread_out     good move
2895           lca       1,dl                just zap first word
2896           sta       cme_0,*.cme
2897           asa       sst|sst.nused       it's not used.
2898           tsx       .ret,page_error$deleting_mm_frame annuntio
2899           tra       unsavex
2900 
2901 "
2902 "         Subroutine to call disk_emergency on disk-errors,
2903 "         So that he might make assessments of system-wide
2904 "         implications of disk device status.
2905 
2906 call_disk_emergency:
2907           sta       pvtx                pvtx in a-reg
2908           eppap     pvtx
2909           spriap    arg+2
2910           eppap     errcode
2911           spriap    arg+4
2912           ldaq      =v18/4,18/4,36/0
2913           staq      arg
2914           call      disk_emergency$disk_emergency(sp|arg)
2915           tra       0,.ret
2916 
2917 
2918           end