date and time created 85/07/24 12:58:34 by sam
authorSam Leffler <sam@ucbvax.Berkeley.EDU>
Thu, 25 Jul 1985 03:58:34 +0000 (19:58 -0800)
committerSam Leffler <sam@ucbvax.Berkeley.EDU>
Thu, 25 Jul 1985 03:58:34 +0000 (19:58 -0800)
SCCS-vsn: sys/tahoe/tahoe/locore.s 1.1

usr/src/sys/tahoe/tahoe/locore.s [new file with mode: 0644]

diff --git a/usr/src/sys/tahoe/tahoe/locore.s b/usr/src/sys/tahoe/tahoe/locore.s
new file mode 100644 (file)
index 0000000..f3c9d2e
--- /dev/null
@@ -0,0 +1,1402 @@
+/*     locore.s        1.7     85/05/15        */
+
+#include "../tahoe/mtpr.h"
+#include "../tahoe/trap.h"
+#include "../tahoe/psl.h"
+#include "../tahoe/pte.h"
+#include "../tahoe/cp.h"
+#include "../tahoe/mem.h"
+#include "../tahoe/fp.h"
+
+#include "../h/errno.h"
+
+       .set    HIGH,0x1f       # mask for total disable
+       .set    BERVEC,0x80     # offset into scb of the bus error vector 
+       .set    RESTVEC,0x8     # offset into scb of the restart vector 
+       .set    MAXPHYSMEM,8*1024*1024-1 # max physical memory 
+                                       # while we work on CMD/32M !
+                                       # look at vmsched.c to see why.
+       .set    MEMUNIT,64*1024 # minimum memory increment
+
+       .set    NISP,3          # number of interrupt stack pages
+       .set    SYSTEM,0xC0000000 # virtual address of system start
+       .set    PPAGES,0x100000  # Number of possible pages in P0,P1, etc.
+
+/* ACBL for non-negative '_add' */
+#define ACBL(_limit,_add,_index,_displ) \
+       addl2   _add,_index; \
+       cmpl    _index,_limit; \
+       bleq    _displ
+
+/* _ACBL for negative '_add' */
+#define _ACBL(_limit,_add,_index,_displ) \
+       addl2   _add,_index; \
+       cmpl    _index,_limit; \
+       bgeq    _displ
+
+#define        MOVC3(_len,_srcaddr,_dstaddr) \
+       movl    _srcaddr,r0; \
+       movl    _dstaddr,r1; \
+       movl    _len,r2; \
+       movblk
+
+/* Keep address of psl if coming from user mode */
+#define CHECK_SFE(_delta) \
+       bitl    $PSL_CURMOD,_delta(sp); \
+       jeql    1f; \
+       moval   _delta(sp),_user_psl; \
+1:
+
+/*
+ * User structure is UPAGES at top of user space.
+ */
+       .globl  _u
+       .set    _u,SYSTEM - UPAGES*NBPG
+
+/*
+ * Restart stack. Used on power recovery or panic.
+ * Takes a core-dump and then halts.
+ */ 
+       .globl  _rsstk
+
+_rsstk:        .space  1024-8
+       .globl  pwfl_stk        
+pwfl_stk:      .space  4
+dumpflag:      .space  4
+
+       .globl  _intstack
+_intstack:
+       .space  NISP*NBPG
+eintstack:
+
+       .data
+       .globl  pwfl_r0
+pwfl_r0:       .space  14*4            # Enough for r0 - r13
+       .globl  pwfl_sp
+pwfl_sp:       .long   0x12345678      # r14
+       .globl  pwfl_SCBB
+pwfl_SCBB:     .long   0x12345678
+       .globl  pwfl_SBR
+pwfl_SBR:      .long   0x12345678
+       .globl  pwfl_SLR
+pwfl_SLR:      .long   0x12345678
+       .globl  pwfl_P0BR
+pwfl_P0BR:     .long   0x12345678
+       .globl  pwfl_P0LR
+pwfl_P0LR:     .long   0x12345678
+       .globl  pwfl_P1BR
+pwfl_P1BR:     .long   0x12345678
+       .globl  pwfl_P1LR
+pwfl_P1LR:     .long   0x12345678
+       .globl  pwfl_P2BR
+pwfl_P2BR:     .long   0x12345678
+       .globl  pwfl_P2LR
+pwfl_P2LR:     .long   0x12345678
+       .globl  pwfl_IPL
+pwfl_IPL:      .long   0x12345678
+       .globl  pwfl_DCK
+pwfl_DCK:      .long   0x12345678
+       .globl  pwfl_CCK
+pwfl_CCK:      .long   0x12345678
+       .globl  pwfl_PCBB
+pwfl_PCBB:     .long   0x12345678
+       .globl  pwfl_ISP
+pwfl_ISP:      .long   0x12345678
+       .globl  pwfl_KSP
+pwfl_KSP:      .long   0x12345678
+       .globl  pwfl_USP
+pwfl_USP:      .long   0x12345678
+       .globl  pwfl_MME
+pwfl_MME:      .long   0x12345678
+       .globl  pwfl_PSL
+pwfl_PSL:      .long   0x12345678
+
+/*
+ * Do a dump.
+ * Called by auto-restart.
+ * May be called manually.
+ */
+       .align  2
+       .text
+       .globl  _Xdoadump
+       .globl  _doadump
+_Xdoadump:                     # CP brings Tahoe here on power recovery
+       loadr   $0x3fff,pwfl_r0 # Restore r0 - r13
+       movl    pwfl_sp,sp      # Restore sp ( = r14 )
+       mtpr    pwfl_SCBB,$SCBB
+       mtpr    pwfl_SBR,$SBR   # Restore all re_loadable registers
+       mtpr    pwfl_SLR,$SLR
+       mtpr    pwfl_P0BR,$P0BR
+       mtpr    pwfl_P0LR,$P0LR
+       mtpr    pwfl_P1BR,$P1BR
+       mtpr    pwfl_P1LR,$P1LR
+       mtpr    pwfl_P2BR,$P2BR
+       mtpr    pwfl_P2LR,$P2LR
+       mtpr    pwfl_IPL,$IPL
+       mtpr    pwfl_DCK,$DCK
+       mtpr    pwfl_CCK,$CCK
+       mtpr    pwfl_PCBB,$PCBB
+       mtpr    pwfl_ISP,$ISP
+       mtpr    pwfl_KSP,$KSP
+       mtpr    pwfl_USP,$USP
+
+       bicpsw  $0xff           # Restore PSW.
+       bispsw  pwfl_PSL+2      # Set original bits back (just in case..)
+/* now go to mapped mode */
+/* Have to change PC to system addresses */
+       mtpr    $1,$PACC        # Thoroughly clean up caches.
+       mtpr    $1,$PADC
+       mtpr    $1,$TBIA
+       mtpr    pwfl_MME,$MME   # Restore MME. Last thing to be done.
+       jmp     *$0f
+_doadump:
+       .word 0
+#define        _rsstkmap       _Sysmap+12                      
+                       # Tahoe storage, scb, rsstk, interrupt stack
+0:
+       mtpr    $HIGH,$IPL
+       andl2   $0!PG_PROT,_rsstkmap
+       orl2    $PG_KW,_rsstkmap                # Make dump stack r/w
+       tstl    dumpflag                        # dump only once!
+       bneq    1f
+       movl    $1,dumpflag
+       mtpr    $0,$TBIA
+       movab   dumpflag,sp
+       callf   $4,_dumpsys
+1:
+       halt
+
+/*
+ * Interrupt vector routines
+ */ 
+       .globl  _waittime
+
+#define        SCBVEC(name) \
+       .align 2; \
+       .globl _X/**/name; \
+_X/**/name
+#define        PANIC(msg)      clrl _waittime; pushab 1f; \
+                       callf $8,_panic; 1: .asciz msg
+#define        PRINTF(n,msg)   pushab 1f; callf $(n+2)*4,_printf; MSG(msg)
+#define        MSG(msg)        .data; 1: .asciz msg; .text
+
+                       # these registers are not restored by the C-compiler.
+#define        PUSHR           pushl r0; pushl r1;
+#define        POPR            movl (sp)+, r1; movl (sp)+, r0;
+                       # mask for error code on stack.
+
+#define SAVE_FPSTAT(_delta)    bitl    $PSL_DBL,_delta(sp); \
+                               beql    1f; \
+                               pushl   $1; \
+                               pushd; \
+                               jmp     2f; \
+                       1:      pushl   $0; \
+                               pushl   $0; \
+                               stf     -(sp); \
+                       2:      tstl    _u+PCB_SAVACC; \
+                               bneq    3f; \
+                               moval   0(sp),_u+PCB_SAVACC; \
+                               orl2    $2,8(sp);\
+                       3:      pushl   $0;
+
+#define REST_FPSTAT            tstl    (sp)+; \
+                               bitl    $2,8(sp);\
+                               beql    1f;\
+                               movl    $0,_u+PCB_SAVACC; \
+                       1:      bitl    $1,8(sp); \
+                               beql    2f; \
+                               ldd     (sp); \
+                               jmp     3f; \
+                       2:      ldf     (sp); \
+                       3:      moval   12(sp),sp;
+
+#define REST_ACC               tstl    _u+PCB_SAVACC; \
+                               beql    2f; \
+                               movl    _u+PCB_SAVACC,r1; \
+                               andl3   $(EXPMASK|SIGNBIT),(r1),-(sp); \
+                               cmpl    $0x80000000,(sp)+; \
+                               bneq    3f; \
+                               clrl    (r1); \
+                       3:      bitl    $1,8(r1); \
+                               beql    1f; \
+                               ldd     (r1); \
+                               jmp     2f; \
+                       1:      ldf     (r1); \
+                       2:      ;
+
+#define PUSHBPAR       pushab  6*4(sp) /* Push address of buserr paramters */
+#define BPAR1          28              /* Offset to first hardware parameter */
+
+SCBVEC(buserr):
+       CHECK_SFE(12)
+       SAVE_FPSTAT(12);
+       PUSHR
+       andl3   BPAR1(sp),$ERRCD,r0
+       jeql    go_on
+       cmpl    r0,$APE
+       jneq    1f
+       halt            # Address parity error !!!
+1:     cmpl    r0,$VBE
+       jneq    go_on
+       halt            # Versabus error !!!
+go_on:
+       PUSHBPAR        # Pointer to parameters
+       callf   $8,_buserror
+       POPR
+       REST_FPSTAT;
+       movab   8(sp),sp        # Remove hardware parameters
+       rei
+
+SCBVEC(powfail):               # We should be on interrupt stack now.
+       movpsl  pwfl_PSL        # Keeps all flags, etc.
+       storer  $0x3fff,pwfl_r0 # Saves r0 - r13
+       moval   0(sp),pwfl_sp   # Saves sp ( = r14 )
+       mfpr    $SBR,pwfl_SBR   # Save all re_loadable registers
+       mfpr    $SLR,pwfl_SLR
+       mfpr    $P0BR,pwfl_P0BR
+       mfpr    $P0LR,pwfl_P0LR
+       mfpr    $P1BR,pwfl_P1BR
+       mfpr    $P1LR,pwfl_P1LR
+       mfpr    $P2BR,pwfl_P2BR
+       mfpr    $P2LR,pwfl_P2LR
+       mfpr    $IPL,pwfl_IPL
+       mfpr    $MME,pwfl_MME  
+       mfpr    $DCK,pwfl_DCK
+       mfpr    $CCK,pwfl_CCK
+       mfpr    $PCBB,pwfl_PCBB
+       mfpr    $ISP,pwfl_ISP
+       mfpr    $SCBB,pwfl_SCBB
+       mfpr    $KSP,pwfl_KSP
+       mfpr    $USP,pwfl_USP
+       moval   _Xdoadump-SYSTEM,_scb+RESTVEC
+       halt
+
+SCBVEC(stray):
+       PUSHR; PRINTF(0, "******* Undefined interrupt *******\n"); POPR;
+       rei
+
+#include "../net/netisr.h"
+       .globl  _netisr
+SCBVEC(netintr):
+       CHECK_SFE(4)
+       SAVE_FPSTAT(4)
+       PUSHR
+
+       bbc     $NETISR_RAW,_netisr,1f
+       andl2   $(0!(1<<NETISR_RAW)),_netisr    
+       callf   $4,_rawintr     
+1:
+#ifdef INET
+#include "../netinet/in_systm.h"
+       bbc     $NETISR_IP,_netisr,1f   
+       andl2   $(0!(1<<NETISR_IP)),_netisr
+       callf   $4,_ipintr      
+1:
+#endif
+#ifdef NS
+       bbc     $NETISR_NS,_netisr,1f   
+       andl2   $(0!(1<<NETISR_NS)),_netisr
+       callf   $4,_nsintr      
+1:
+#endif
+       POPR; 
+       REST_FPSTAT
+       rei
+SCBVEC(soft15):
+SCBVEC(soft14):
+SCBVEC(soft13):
+SCBVEC(soft11):
+SCBVEC(soft10):
+#ifndef SIMIO
+SCBVEC(soft9):
+#endif
+SCBVEC(soft7):
+SCBVEC(soft6):
+SCBVEC(soft5):
+SCBVEC(soft4):
+#ifndef SIMIO
+SCBVEC(soft3):
+SCBVEC(soft2):
+SCBVEC(soft1):
+#endif
+       PUSHR
+       PRINTF(0, "******* Undefined software interrupt *******\n")
+       POPR;
+       rei
+
+#ifdef SIMIO
+SCBVEC(soft2):
+#endif
+SCBVEC(cnrint):
+       CHECK_SFE(4)
+       SAVE_FPSTAT(4);PUSHR; 
+       pushl $CPCONS; callf $8,_cnrint; POPR; incl _cnt+V_INTR;
+       REST_FPSTAT; rei
+#ifdef SIMIO
+SCBVEC(soft3):
+#endif
+SCBVEC(cnxint):
+       CHECK_SFE(4)
+       SAVE_FPSTAT(4);PUSHR; 
+       pushl $CPCONS; callf $8,_cnxint; POPR; REST_FPSTAT;
+       incl _cnt+V_INTR; rei
+SCBVEC(rmtrint):
+       CHECK_SFE(4)
+       SAVE_FPSTAT(4); PUSHR; 
+       pushl $CPREMOT; callf $8,_cnrint; POPR; REST_FPSTAT;
+       incl _cnt+V_INTR; rei
+SCBVEC(rmtxint):
+       CHECK_SFE(4)
+       SAVE_FPSTAT(4); PUSHR; 
+       pushl $CPREMOT; callf $8,_cnxint; POPR; REST_FPSTAT;
+       incl _cnt+V_INTR; rei
+#ifdef SIMIO
+SCBVEC(soft9):
+#endif
+
+#define PUSHPCPSL      pushl 5*4+2*4(sp); pushl 5*4+2*4(sp);
+
+SCBVEC(hardclock):
+       CHECK_SFE(4)
+       SAVE_FPSTAT(4)
+       PUSHR
+       PUSHPCPSL                               # push pc and psl
+       callf $12,_hardclock                    # hardclock(pc,psl)
+       POPR;
+       REST_FPSTAT
+       incl    _cnt+V_INTR             ## temp so not to break vmstat -= HZ
+       rei
+SCBVEC(softclock):
+       CHECK_SFE(4)
+       SAVE_FPSTAT(4)
+       PUSHR
+       PUSHPCPSL                               # push pc and psl
+       callf $12,_softclock                    # softclock(pc,psl)
+       POPR; 
+       REST_FPSTAT
+       rei
+
+/*
+ * Trap and fault vector routines
+ */ 
+#define        TRAP(a) pushl $T_/**/a; jbr alltraps
+
+/*
+ * Ast delivery (profiling and/or reschedule)
+ */
+/*
+ * When we want to reschedule we will force a memory fault by setting the m.s.b
+ *  of P0LR. Then , on memory fault if m.s.b of P0LR is on we will clear it and
+ *  TRAP(astflt).
+ *
+ */
+                                       # if this bit is on it is an ast.
+#define        ASTBIT  0x00100000      
+#define                P0MASK  0xc0000000
+
+SCBVEC(kspnotval):
+       CHECK_SFE(4)
+       pushl $0;
+       SAVE_FPSTAT(8)
+       TRAP(KSPNOTVAL)
+SCBVEC(privinflt):
+       CHECK_SFE(4)
+       pushl $0;
+       SAVE_FPSTAT(8)
+       TRAP(PRIVINFLT)
+SCBVEC(resopflt):
+       CHECK_SFE(4)
+       pushl $0;
+       SAVE_FPSTAT(8)
+       TRAP(RESOPFLT)
+SCBVEC(resadflt):
+       CHECK_SFE(4)
+       pushl $0;
+       SAVE_FPSTAT(8)
+       TRAP(RESADFLT)
+SCBVEC(bptflt):
+       CHECK_SFE(4)
+       pushl $0;
+       SAVE_FPSTAT(8)
+       TRAP(BPTFLT)
+SCBVEC(tracep):
+       CHECK_SFE(4)
+       pushl $0;
+       SAVE_FPSTAT(8)
+       TRAP(TRCTRAP)
+SCBVEC(alignflt):
+       CHECK_SFE(4)
+       pushl $0;
+       SAVE_FPSTAT(8)
+       TRAP(ALIGNFLT)
+SCBVEC(arithtrap):
+       CHECK_SFE(8)
+       SAVE_FPSTAT(8)
+       TRAP(ARITHTRAP)
+
+SCBVEC(protflt):
+       CHECK_SFE(12)
+       bitl    $1,(sp)+
+       jneq    segflt
+       SAVE_FPSTAT(8)
+       TRAP(PROTFLT)
+segflt:
+       SAVE_FPSTAT(8)
+       TRAP(SEGFLT)
+
+SCBVEC(fpm):                   # Floating Point eMulation
+       .globl  _fpemulate
+       CHECK_SFE(16)
+       SAVE_FPSTAT(16)
+       callf   $4,_fpemulate
+       REST_FPSTAT
+       moval   8(sp),sp        # Pop operand
+       tstl    (sp)            # Stack= PSL, PC, return_code
+       jneq    _Xarithtrap     # If not OK, emulate F.P. exception
+       movab   4(sp),sp        # Else remove return_code and
+       rei
+
+SCBVEC(sfexcep):
+       CHECK_SFE(4)
+       pushl $0
+       SAVE_FPSTAT(8)
+       TRAP(ASTFLT)
+
+SCBVEC(transflt):
+       CHECK_SFE(12)
+       bitl    $1,(sp)+
+       bneq    tableflt
+pageflt:
+       SAVE_FPSTAT(8)
+       TRAP(PAGEFLT)
+tableflt:
+       SAVE_FPSTAT(8)
+       TRAP(TABLEFLT)
+
+#define REST_STACK     movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
+
+alltraps:
+       mfpr    $USP,-(sp); 
+       callf $4,_trap; mtpr (sp)+,$USP
+       incl    _cnt+V_TRAP
+       REST_STACK                      # pop type, code, an fp stuff
+       mtpr    $HIGH,$IPL              ## dont go to a higher IPL (GROT)
+       rei
+
+SCBVEC(syscall):
+       CHECK_SFE(8)
+       SAVE_FPSTAT(8)
+       pushl   $T_SYSCALL
+       mfpr    $USP,-(sp); callf $4,_syscall; mtpr (sp)+,$USP
+       incl    _cnt+V_SYSCALL
+       REST_STACK                      # pop type, code, an fp stuff
+       mtpr    $HIGH,$IPL              ## dont go to a higher IPL (GROT)
+       rei
+
+/*
+ * System page table
+ */ 
+#define        vaddr(x)        ((((x)-_Sysmap)/4)*NBPG+SYSTEM)
+#define        SYSMAP(mname, vname, npte)                      \
+_/**/mname:    .globl  _/**/mname;             \
+       .space  npte*4;                         \
+       .globl  _/**/vname;                     \
+       .set    _/**/vname,vaddr(_/**/mname)
+
+       .data
+       .align  2
+       SYSMAP(Sysmap   ,Sysbase        ,SYSPTSIZE      )
+       SYSMAP(VMEMbeg  ,vmembeg        ,0              )
+       SYSMAP(VMEMmap  ,vmem           ,IOSIZE         )
+       SYSMAP(ACE0map  ,ace0utl        ,(ACEBPTE+1)    )
+       SYSMAP(ACE1map  ,ace1utl        ,(ACEBPTE+1)    )
+       SYSMAP(VMEMend  ,vmemend        ,0              )
+       SYSMAP(Usrptmap ,usrpt          ,USRPTSIZE      )
+       SYSMAP(Forkmap  ,forkutl        ,UPAGES         )
+       SYSMAP(Xswapmap ,xswaputl       ,UPAGES         )
+       SYSMAP(Xswap2map,xswap2utl      ,UPAGES         )
+       SYSMAP(Swapmap  ,swaputl        ,UPAGES         )
+       SYSMAP(Pushmap  ,pushutl        ,UPAGES         )
+       SYSMAP(Vfmap    ,vfutl          ,UPAGES         )
+       SYSMAP(VD0map   ,vd0utl         ,(MAXBPTE+1)    )
+       SYSMAP(VD1map   ,vd1utl         ,(MAXBPTE+1)    )
+       SYSMAP(VD2map   ,vd2utl         ,(MAXBPTE+1)    )
+       SYSMAP(VD3map   ,vd3utl         ,(MAXBPTE+1)    )
+       SYSMAP(CYmap    ,cyutl          ,(TBUFSIZ+1)    )
+       SYSMAP(CMAP1    ,CADDR1         ,1              )
+       SYSMAP(CMAP2    ,CADDR2         ,1              )
+       SYSMAP(mmap     ,vmmap          ,1              )
+       SYSMAP(msgbufmap,msgbuf         ,MSGBUFPTECNT   )
+       SYSMAP(camap    ,cabase         ,16*CLSIZE      )
+       SYSMAP(ecamap   ,calimit        ,0              )
+       SYSMAP(Mbmap    ,mbutl          ,NMBCLUSTERS*CLSIZE)
+eSysmap:
+       .globl  _Syssize
+       .set    _Syssize,(eSysmap-_Sysmap)/4
+
+       .text
+/*
+ * Initialization
+ *
+ * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
+ *
+ */
+
+       .align  2
+       .globl  start
+start:
+       .word   0
+
+/* set system control block base and system page table params */
+
+       mtpr    $_scb-SYSTEM,$SCBB
+       mtpr    $_Sysmap-SYSTEM,$SBR
+       mtpr    $_Syssize,$SLR
+
+/* double map the kernel into the virtual user addresses of phys mem */
+/* (to be on the safe side.This is supposed to run in system sace. )  */
+       mtpr    $_Sysmap,$P0BR
+       mtpr    $_Syssize,$P0LR
+
+       mtpr    $_Sysmap,$P1BR          # Against Murphy
+       mtpr    $_Syssize,$P1LR
+
+/* set ISP */
+       movl    $_intstack-SYSTEM+NISP*NBPG,sp  # Still physical !
+       mtpr    $_intstack+NISP*NBPG,$ISP
+
+/* count up memory */
+
+       clrl    r7
+1:     pushl   $1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
+       addl2   $MEMUNIT,r7
+       cmpl    r7,$MAXPHYSMEM
+       bleq    1b
+9:
+/* clear memory from kernel bss and pages for proc 0 u. and page table */
+       movab   _edata,r6
+       movab   _end,r5
+       andl2   $0!SYSTEM,r6
+       andl2   $0!SYSTEM,r5
+       addl2   $(UPAGES*NBPG)+NBPG+NBPG,r5
+1:     clrl    (r6); ACBL( r5,$4,r6,1b)
+
+/* trap() and syscall() save r0-r13 in the entry mask (per ../h/reg.h) */
+/* For floating point emulation, we do same for 'fpemulate' */
+       orw2    $0x01fff,_trap
+       orw2    $0x01fff,_syscall
+       orw2    $0x01fff,_fpemulate
+
+/* initialize system page table: scb and int stack writeable */
+       clrl    r2
+       movab   eintstack,r1 
+       andl2   $0!SYSTEM,r1
+       shrl    $PGSHIFT,r1,r1          # r1-page number of eintstack.
+
+/* Start by making the processor storage read/only */
+
+       orl3    $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
+       orl3    $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
+
+/* Other parts of the system are read/write for kernel */
+
+1:     orl3    $PG_V|PG_KW,r2,_Sysmap[r2]; # data:kernel write + phys=virtual
+       aoblss r1,r2,1b
+
+/* make rsstk read-only as red zone for interrupt stack */
+       andl2   $0!PG_PROT,_rsstkmap
+       orl2    $PG_V|PG_KR,_rsstkmap           # Make dump stack r/w
+
+/* make kernel text space read-only */
+/*
+ * HAVE TO CHECK ALL THE MAGIC CONSTANTS USED HERE : $xxxxxx */
+
+       movab   _etext+NBPG-1,r1
+       andl2   $0!SYSTEM,r1
+       shrl    $PGSHIFT,r1,r1
+1:     orl3    $PG_V|PG_KR,r2,_Sysmap[r2]
+       aoblss r1,r2,1b
+
+/* make kernel data, bss, read-write */
+       movab   _end+NBPG-1,r1
+       andl2   $0!SYSTEM,r1
+       shrl    $PGSHIFT,r1,r1
+1:     orl3    $PG_V|PG_KW,r2,_Sysmap[r2]
+       aoblss r1,r2,1b
+
+/* now go to mapped mode */
+/* Have to change both PC and SP to system addresses */
+       mtpr    $1,$TBIA
+       mtpr    $1,$PADC        /* needed by HW parity & ECC logic */
+       mtpr    $1,$PACC        /* just in case */
+       mtpr    $1,$MME
+       movab   SYSTEM(sp),sp
+       .globl  go_virt
+go_virt:       
+       jmp     *$0f
+0:
+
+/* disable any interrupts */
+       movl    $0,_intenable
+/* init mem sizes */
+       shrl    $PGSHIFT,r7,_maxmem
+       movl    _maxmem,_physmem
+       movl    _maxmem,_freemem
+
+/* setup context for proc[0] == Scheduler */
+       movab   _end-SYSTEM+NBPG-1,r6
+       andl2   $0!(NBPG-1),r6          # make page boundary
+
+/* setup page table for proc[0] */
+       shrl    $PGSHIFT,r6,r3                  # r3 = btoc(r6)
+       orl3    $PG_V|PG_KW,r3,_Usrptmap        # init first upt entry
+       incl    r3                              # r3 - next page
+       movab   _usrpt,r0                       # r0 - first user page
+       mtpr    r0,$TBIS
+
+/* init p0br, p0lr */
+       mtpr    r0,$P0BR        # No P0 for proc[0]
+       mtpr    $0,$P0LR
+
+       mtpr    r0,$P1BR        # No P1 either
+       mtpr    $0,$P1LR
+
+
+/* init p2br, p2lr */
+       movab   NBPG(r0),r0
+       movl    $PPAGES-UPAGES,r1
+       mtpr    r1,$P2LR
+       moval   -4*PPAGES(r0),r2
+       mtpr    r2,$P2BR
+
+/* setup mapping for UPAGES of _u */
+       clrl    r2; 
+       movl    $SYSTEM,r1
+       addl2   $UPAGES,r3
+       jbr 2f
+1:     decl    r3
+       moval   -NBPG(r1),r1;   # r1 = virtual add of next (downward) _u page
+       subl2   $4,r0           # r0 = pte address
+       orl3    $PG_V|PG_URKW,r3,(r0)
+       mtpr    r1,$TBIS
+2:     aobleq  $UPAGES,r2,1b
+
+/* initialize (slightly) the pcb */
+       movab   UPAGES*NBPG(r1),PCB_KSP(r1)     # KSP starts at end of _u
+       movl    r1,PCB_USP(r1)                  # USP starts just below _u
+       mfpr    $P0BR,PCB_P0BR(r1)
+       mfpr    $P0LR,PCB_P0LR(r1)
+       mfpr    $P1BR,PCB_P1BR(r1)
+       mfpr    $P1LR,PCB_P1LR(r1)
+       mfpr    $P2BR,PCB_P2BR(r1)
+       mfpr    $P2LR,PCB_P2LR(r1)
+       movl    $CLSIZE,PCB_SZPT(r1)            # init u.u_pcb.pcb_szpt
+       movl    r11,PCB_R11(r1)                 # r11 obtained from CP on boot
+       movab   1f,PCB_PC(r1)                   # initial pc
+       clrl    PCB_PSL(r1)                     # kernel mode, ipl=0
+       movw    $0xff,PCB_CKEY(r1)      # give him a code key
+       movw    $0xff,PCB_DKEY(r1)      # give him a data key
+       shll    $PGSHIFT,r3,r3
+       mtpr    r3,$PCBB                        # first pcbb (physical ! )
+
+/* Go to a 'normal' process mode (kernel) */
+
+       ldpctx
+       rei             # Actually 'returns' to the next instruction:
+
+/* put signal trampoline code in u. area */
+1:     movab   _u,r0
+       movl    sigcode+0,PCB_SIGC+0(r0)
+       movl    sigcode+4,PCB_SIGC+4(r0)
+       movl    sigcode+8,PCB_SIGC+8(r0)
+       movl    sigcode+12,PCB_SIGC+12(r0)
+
+/* save reboot flags in global _boothowto */
+       movl    r11,_boothowto
+
+/* calculate firstaddr, and call main() */
+       movab   _end-SYSTEM+NBPG-1,r0
+       shrl    $PGSHIFT,r0,-(sp)
+       addl2   $UPAGES+1,(sp)          # First physical unused page number
+       callf   $8,_main
+
+/* proc[1] == /etc/init now running here in kernel mode; run icode */
+       pushl   $PSL_CURMOD             # User mode PSL
+       pushl $0                        # PC = 0 (virtual now)
+       rei
+
+/* signal trampoline code: it is known that this code takes up to 16    */
+/* bytes in pcb.h and in the code above                                */
+/*  The following user stack layout was set up by machdep.c/sendsig    */
+/*     routine:                                                        */
+/*                                                                     */
+/*     +---------------+                                               */
+/*     |  Last PSL     |\                                              */
+/*     +---------------+ > for rei                                     */
+/*  :-->|  Last PC     |/                                              */
+/*  |  +---------------+                                               */
+/*  :___|__*   SP      |\                                              */
+/*     +---------------+ |                                             */
+/*     |  sigmask      | |                                             */
+/*     +---------------+  > cleaned by kcall $139 (sigcleanup)         */
+/*  :-->|  u.u_onstack | |                                             */
+/*  |  +---------------+ |                                             */
+/*  :___|_* copy of SCP        |/                                              */
+/*  |  +---------------+                                               */
+/*  |  |  Process' r0  |                                               */
+/*  |  +---------------+                                               */
+/*  |  |  Process' r1  |                                               */
+/*  |  +---------------+                                               */
+/*  |  | Handler addr. |\                                              */
+/*  |  +---------------+ |                                             */
+/*  :___|_*   SCP      | |                                             */
+/*     +---------------+  > cleaned by ret from calls                  */
+/*     |  u.u_code     | |                                             */
+/*     +---------------+ |                                             */
+/*     |  signal number|/                                              */
+/*     +---------------+                                               */
+/*                                                                     */
+/*   * Stack when entering sigcode; setup by sendsig();                        */
+/*                                                                     */
+       .align  2
+sigcode:                       # When the process executes this code
+                               #  (located in its u. structure), it
+                               #  is in user mode !
+       calls   $4*4+4,*12(sp)  # 4 words popped from stack when this call returns
+       movl    (sp)+,r1
+       movl    (sp)+,r0
+       kcall   $139            # Signal cleanup
+       rei                     # From user mode to user mode !
+
+/*
+ * Primitives
+ */ 
+
+/*
+ * badaddr(addr, len)
+ *     see if access addr with a len type instruction causes a machine check
+ *     len is length of access (1=byte, 2=short, 4=long)
+ *     r0 = 0 means good(exists); r0 =1 means does not exist.
+ */
+       .globl  _badaddr
+_badaddr:
+       .word   0x1c    # Keep r4,r3,r2
+       mfpr    $IPL,r1
+       mtpr    $HIGH,$IPL
+       movl    _scb+BERVEC,r2
+       movl    4(fp),r3
+       movl    8(fp),r4
+       movab   9f,_scb+BERVEC
+       bbc     $0,r4,1f; tstb  (r3)
+1:     bbc     $1,r4,1f; tstw  (r3)
+1:     bbc     $2,r4,1f; tstl  (r3)
+1:     clrl    r0                      # made it w/o machine checks
+2:     movl    r2,_scb+BERVEC
+       mtpr    r1,$IPL
+       ret
+
+       .align  2
+9:                     # Here we catch buss error (if it comes)
+       andl3   4(sp),$ERRCD,r0
+       cmpl    r0,$APE
+       jneq    1f
+       halt                    # Address parity error !!!
+1:     cmpl    r0,$VBE
+       jneq    1f
+       halt                    # Versabus error
+1:
+       movl    $1,r0           # Anything else = bad address
+       movab   8(sp),sp        # discard buss error trash
+       movab   2b,(sp)         # new program counter on stack.
+       rei
+
+
+/*
+ * badcyaddr(addr)
+ *     see if access tape master controller addr causes a bus error
+ *     r0 = 0: no error; r0 = 1: timeout error.
+ */
+       .globl  _badcyaddr
+_badcyaddr:
+       .word   0x0c    # Keep r3,r2
+       mfpr    $IPL,r1
+       mtpr    $HIGH,$IPL
+       movl    _scb+BERVEC,r2
+       clrl    r3
+       movab   9f,_scb+BERVEC
+       movob   $-1, *4(fp)
+1:     aobleq  $1000, r3, 1b
+       clrl    r0                      # made it w/o machine checks
+2:     movl    r2,_scb+BERVEC
+       mtpr    r1,$IPL
+       ret
+
+       .align  2
+9:                     # Here we catch buss error (if it comes)
+       andl3   4(sp),$ERRCD,r0
+       cmpl    r0,$APE
+       jneq    1f
+       halt                    # Address parity error !!!
+1:     cmpl    r0,$VBE
+       jneq    1f
+       halt                    # Versabus error
+1:
+       movl    $1,r0           # Anything else = timeout
+       movab   8(sp),sp        # discard buss error trash
+       movab   2b,(sp)         # new program counter on stack.
+       rei
+
+_bcopy:        .globl  _bcopy
+       .word   0x4             # save r2
+                               # Called by ovbcopy(from,dst,len)
+       movl    4(fp),r0
+       movl    8(fp),r1
+       movl    12(fp),r2
+       movblk
+       ret
+
+_ovbcopy:      .globl  _ovbcopy
+       .word   0x001c
+       movl    4(fp),r0
+       movl    8(fp),r1
+       movl    12(fp),r2
+       cmpl    r0,r1
+       bgtru   1f              # normal forward case
+       beql    2f              # equal, nothing to do
+       addl2   r2,r0           # may be overlapping
+       cmpl    r0,r1
+       bgtru   3f
+       subl2   r2,r0           # normal forward case
+1:
+       movblk
+2:
+       ret
+3:
+       addl2   r2,r1           # overlapping, must do backwards
+       subl3   r0,r1,r3
+       movl    r2,r4
+       jbr     5f
+4:
+       subl2   r3,r0
+       subl2   r3,r1
+       movl    r3,r2
+       movblk
+       subl2   r3,r0
+       subl2   r3,r1
+       subl2   r3,r4
+5:
+       cmpl    r4,r3
+       jgtr    4b
+       movl    r4,r2
+       subl2   r2,r0
+       subl2   r2,r1
+       movblk
+       ret
+
+/*
+ * bzero (base, count)
+ * zero out a block starting at 'base', size 'count'.
+ */
+_bzero:        
+       .globl  _bzero
+       .word   0x4
+       movl    $1f,r0                          # r0 = null source string
+       movl    4(fp),r1                        # r1 = destination address
+       movl    8(fp),r2                        # r2 = count
+       movs3
+       ret
+1:
+       .byte 0
+
+
+_copyin:       .globl  _copyin         # the _Copyin subroutine in VAX
+                                       # became _copyin procedure for TAHOE
+       .word   0x0004
+       movl    12(fp),r0               # copy length
+       blss    ersb
+       movl    4(fp),r1                # copy user address
+       cmpl    $NBPG,r0                # probing one page or less ?
+       bgeq    cishort                 # yes
+ciloop:
+       prober  $1,(r1),$NBPG           # bytes accessible ?
+       beql    ersb                    # no
+       addl2   $NBPG,r1                # incr user address ptr
+       _ACBL   ($NBPG+1,$-NBPG,r0,ciloop)      # reduce count and loop
+cishort:
+       prober  $1,(r1),r0              # bytes accessible ?
+       beql    ersb                    # no
+       MOVC3   (12(fp),4(fp),8(fp))
+       clrl    r0
+       ret
+
+ersb:
+       movl    $EFAULT,r0
+       ret
+
+_copyout:      .globl  _copyout        # the _Copyout subroutine in VAX
+                                       # became _copyout procedure for TAHOE
+       .word   0x04
+       movl    12(fp),r0               # get count
+       blss    ersb
+       movl    8(fp),r1                # get user address
+       cmpl    $NBPG,r0                # can do in one probew?
+       bgeq    coshort                 # yes
+coloop:
+       probew  $1,(r1),$NBPG           # bytes accessible?
+       beql    ersb                    # no 
+       addl2   $NBPG,r1                # increment user address
+       _ACBL   ($NBPG+1,$-NBPG,r0,coloop)      # reduce count and loop
+coshort:
+       probew  $1,(r1),r0              # bytes accessible?
+       beql    ersb                    # no
+       MOVC3   (12(fp),4(fp),8(fp))
+       clrl    r0
+       ret
+
+/*
+ * non-local goto's
+ */
+       .globl  _setjmp                 # the _Setjmp subroutine in VAX
+                                       # became _setjmp procedure for TAHOE
+_setjmp:
+       .word   0x0
+       movl    4(fp),r2
+       storer  $0x1ff8,(r2)
+       addl2   $40,r2
+       movl    (fp),(r2)
+       addl2   $4,r2
+       movab   8(fp),(r2)
+       addl2   $4,r2
+       movl    -8(fp),(r2)
+       clrl    r0
+       ret
+
+       .globl  _longjmp                # the _Longjmp subroutine in VAX
+                                       # became _longjmp procedure for TAHOE
+_longjmp:
+       .word   0x0000
+       movl    4(fp),r2
+_Longjmp:                      # called from swtch
+       loadr   $0x3ff8,(r2)
+       addl2   $44,r2
+       movl    (r2),r1
+       addl2   $4,r2
+       movab   (sp),r0
+       cmpl    r1,r0                           # must be a pop
+       bgequ   lj2
+       pushab  lj1
+       callf   $8,_panic
+lj2:
+       movl    r1,sp
+       jmp     *(r2)
+
+lj1:   .asciz  "longjmp"
+
+
+       .globl  _whichqs
+       .globl  _qs
+       .globl  _cnt
+
+       .globl  _noproc
+       .comm   _noproc,4
+       .globl  _runrun
+       .comm   _runrun,4
+
+/*
+ * The following primitives use the fancy TAHOE instructions.
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them.  setrq puts processes into queues, remrq
+ * removes them from queues.  The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+
+/*
+ * setrq(p), using fancy TAHOE instructions.
+ *
+ * Call should be made at spl8(), and p->p_stat should be SRUN
+ */
+       .globl  _setrq
+_setrq:
+       .word   0x4
+       movl    4(fp),r0
+       tstl    P_RLINK(r0)             ## firewall: p->p_rlink must be 0
+       beql    set1                    ##
+       pushab  set3                    ##
+       callf   $8,_panic               ##
+set1:
+       movzbl  P_PRI(r0),r1            # put on queue which is p->p_pri / 4
+       shar    $2,r1,r1
+       shal    $1,r1,r2
+       moval   _qs[r2],r2
+       insque  (r0),*4(r2)             # at end of queue
+       shal    r1,$1,r1
+       orl2    r1,_whichqs             # mark queue non-empty
+       ret
+
+set3:  .asciz  "setrq"
+
+/*
+ * remrq(p), using fancy TAHOE instructions
+ *
+ * Call should be made at spl8().
+ */
+       .globl  _remrq
+_remrq:
+       .word   0x0
+       movl    4(fp),r0
+       movzbl  P_PRI(r0),r1
+       shar    $2,r1,r1
+       bbs     r1,_whichqs,rem1
+       pushab  rem3                    # it wasn't recorded to be on its q
+       callf   $8,_panic
+rem1:
+       remque  (r0)
+       bneq    rem2                    # q not empty yet
+       shal    r1,$1,r1
+       mcoml   r1,r1
+       andl2   r1,_whichqs             # mark queue empty
+rem2:
+       clrl    P_RLINK(r0)             ## for firewall checking
+       ret
+
+rem3:  .asciz  "remrq"
+
+       .globl __insque
+__insque:
+       .word 0
+       insque  *4(fp), *8(fp)
+       ret
+
+
+       .globl __remque
+__remque:
+       .word 0
+       remque  *4(fp)
+       ret
+
+/*
+ * Masterpaddr is the p->p_addr of the running process on the master
+ * processor.  When a multiprocessor system, the slave processors will have
+ * an array of slavepaddr's.
+ */
+       .globl  _masterpaddr
+       .data
+_masterpaddr:
+       .long   0
+
+       .text
+sw0:   .asciz  "swtch"
+/*
+ * swtch(), using fancy TAHOE instructions
+ */
+       .globl  _swtch
+_swtch:
+       .word   0x0
+       movl    (fp),fp                 # prepare for rei
+       movl    (sp),4(sp)              # saved pc
+       tstl    (sp)+
+       movpsl  4(sp)
+       movl    $1,_noproc
+       clrl    _runrun
+mtpr0: mtpr    $0,$IPL                 # must allow interrupts here
+sw1:   ffs     _whichqs,r0             # look for non-empty queue
+       bgeq    sw1a
+       brb     sw1                     # this is an idle loop!
+sw1a:  mtpr    $0x18,$IPL              # lock out all so _whichqs==_qs
+       bbc     r0,_whichqs,mtpr0       # proc moved via lbolt interrupt
+       shal    $1,r0,r1
+       moval   _qs[r1],r1
+       movl    (r1),r2                 # r2 = p = highest pri process
+       remque  *(r1)
+       bvc     sw2                     # make sure something was there
+sw1b:  pushab  sw0
+       callf   $8,_panic
+sw2:   bneq    sw3
+       shal    r0,$1,r1
+       mcoml   r1,r1
+       andl2   r1,_whichqs             # no more procs in this queue
+sw3:
+       clrl    _noproc
+       tstl    P_WCHAN(r2)             ## firewalls
+       bneq    sw1b                    ##
+       movzbl  P_STAT(r2),r3           ##
+       cmpl    $SRUN,r3                ##
+       bneq    sw1b                    ##
+       clrl    P_RLINK(r2)             ##
+       movl    *P_ADDR(r2),r0
+       movl    r0,_masterpaddr
+       shal    $PGSHIFT,r0,r0          # r0 = pcbb(p)
+/*     mfpr    $PCBB,r1                # resume of current proc is easy
+ *     cmpl    r0,r1
+ */    beql    res0
+       incl    _cnt+V_SWTCH
+       brb     swresume
+/* fall into... */
+
+/*
+ * global cache key used if cant use proc index as key
+ * (e.g. NPROC>=255)
+ * otherwise used for temporary storage of key
+ */
+       .data
+       .globl  _globkey
+_globkey:
+       .long   0
+       .globl  _prevpcb
+_prevpcb:
+       .long   0
+       .text
+/*
+ * resume(pf)
+ */
+       .globl  _resume
+_resume:
+       .word   0x0
+       shal    $PGSHIFT,4(fp),r0       # r0 = pcbb(p)
+       movl    (fp),fp                 # prepare for rei
+       movl    (sp)+,4(sp)             # saved pc
+       tstl    (sp)+
+       movpsl  4(sp)
+swresume:
+       mtpr    $0x18,$IPL                      # no interrupts, please
+       movl    _CMAP2,_u+PCB_CMAP2     # yech
+       REST_ACC                        # restore original accumulator
+       svpctx
+       mtpr    r0,$PCBB
+       ldpctx
+       movl    _u+PCB_CMAP2,_CMAP2     # yech
+       mtpr    $_CADDR2,$TBIS
+res0:
+       tstl    _u+PCB_SSWAP
+       beql    res1
+       movl    _u+PCB_SSWAP,r2
+       clrl    _u+PCB_SSWAP
+       movab   _Longjmp,(sp)
+       clrl    4(sp)                   # PSL = kernel mode, IPL=0
+res1:
+#ifdef GLOBKEY
+       aoblss  $256,_globkey,res2      # define new cache key
+       mtpr    $0,$PACC                # out of keys, purge all
+       mtpr    $0,$PADC
+       movl    $1,_globkey
+res2:
+       mtpr    _globkey,$CCK
+#else
+res3:
+       movzwl  _u+PCB_CKEY,_globkey
+       mtpr    _globkey,$CCK
+res4:
+       movzwl  _u+PCB_DKEY,_globkey
+#endif
+       mtpr    _globkey,$DCK
+       rei
+
+/*
+ * {fu,su},{byte,word}
+ */
+       .globl  _fuiword
+       .globl  _fuword
+_fuiword:
+_fuword:
+       .word   0x0
+       movl    4(fp), r1
+       prober  $1,(r1),$4              # check access
+       beql    fserr                   # page unreadable
+       bitl    $1,r1                   # check byte alignment
+       bneq    2f                      # odd, do byte-word-byte
+       bitl    $2,r1                   # check word alignment
+       bneq    1f                      # odd, do in 2 words
+       movl    (r1),r0                 # move longword
+       ret
+1:
+       movw    (r1),r0                 # move two words
+       shal    $16,r0,r0
+       movzwl  2(r1),r1                # orw2 sign extends
+       orl2    r1,r0
+       ret
+2:
+       movb    (r1),r0                 # move byte-word-byte
+       shal    $24,r0,r0
+       movzwl  1(r1),r2                # orw2 sign extends
+       shal    $8,r2,r2
+       movzbl  3(r1),r1                # orb2 sign extends
+       orl2    r2,r1
+       orl2    r1,r0
+       ret
+fserr:
+       mnegl   $1,r0
+       ret
+
+       .globl  _fuibyte
+       .globl  _fubyte
+_fuibyte:
+_fubyte:
+       .word   0x0
+       prober  $1,*4(fp),$1
+       beql    fserr
+       movzbl  *4(fp),r0
+       ret
+
+       .globl  _suiword
+       .globl  _suword
+_suiword:
+_suword:
+       .word   0x0
+       movl    4(fp), r0
+       probew  $1,(r0),$4              # check access
+       beql    fserr                   # page unwritable
+       bitl    $1,r0                   # check byte alignment
+       bneq    1f                      # odd byte boundary
+       bitl    $2,r0                   # check word alignment
+       beql    2f                      # longword aligned
+       movw    8(fp),(r0)              # move two words
+       movw    10(fp),2(r0)
+       jbr     3f
+1:
+       movb    8(fp),(r0)
+       movb    9(fp),1(r0)
+       movb    10(fp),2(r0)
+       movb    11(fp),3(r0)
+       jbr     3f
+2:
+       movl    8(fp),(r0)
+3:
+       clrl    r0
+       ret
+
+       .globl  _suibyte
+       .globl  _subyte
+_suibyte:
+_subyte:
+       .word   0x0
+       probew  $1,*4(fp),$1
+       beql    fserr
+       movb    11(fp),*4(fp)
+       clrl    r0
+       ret
+
+/*
+ * Copy 1 relocation unit (NBPG bytes)
+ * from user virtual address to physical address
+ */
+_copyseg:      .globl  _copyseg
+       .word   0x4
+       orl3    $PG_V|PG_KW,8(fp),_CMAP2
+       mtpr    $_CADDR2,$TBIS  # invalidate entry for copy 
+       MOVC3   ($NBPG,4(fp),$_CADDR2)
+       ret
+
+/*
+ * clearseg(physical_page_number);
+ *
+ * zero out physical memory
+ * specified in relocation units (NBPG bytes)
+ * This routine was optimized for speed on Tahoe.
+ */
+_clearseg:     .globl  _clearseg
+       .word   0
+       orl3    $PG_V|PG_KW,4(fp),_CMAP1        # Maps to virtual addr CADDR1
+       mtpr    $_CADDR1,$TBIS
+       movl    $255,r0                         # r0 = limit
+       clrl    r1                              # r1 = index of cleared long
+1:
+       clrl    _CADDR1[r1]
+       aobleq  r0,r1,1b
+       ret
+
+/*
+ * if ( useracc(address, count, mode) ) ....
+ * Check address.
+ * Given virtual address, byte count, and rw flag
+ * returns 0 on no access.
+ * Note : it is assumed that on all calls to this routine,
+ *  mode=0 means write access, mode=1 means read access.
+ */
+_useracc:      .globl  _useracc
+       .word   0x4
+       movl    $1,r2                   # r2 = 'user mode' for probew/probew
+probes:
+       movl    4(fp),r0                # get va
+       movl    8(fp),r1                # count
+       tstl    12(fp)                  # test for read access ?
+       bneq    userar                  # yes
+       cmpl    $NBPG,r1                        # can we do it in one probe ?
+       bgeq    uaw2                    # yes
+uaw1:
+       probew  r2,(r0),$NBPG
+       beql    uaerr                   # no access
+       addl2   $NBPG,r0
+       _ACBL($NBPG+1,$-NBPG,r1,uaw1)
+uaw2:
+       probew  r2,(r0),r1
+       beql    uaerr
+       movl    $1,r0
+       ret
+
+userar:
+       cmpl    $NBPG,r1
+       bgeq    uar2
+uar1:
+       prober  r2,(r0),$NBPG
+       beql    uaerr
+       addl2   $NBPG,r0
+       _ACBL($NBPG+1,$-NBPG,r1,uar1)
+uar2:
+       prober  r2,(r0),r1
+       beql    uaerr
+       movl    $1,r0
+       ret
+uaerr:
+       clrl    r0
+       ret
+
+/*
+ * if ( kernacc(address, count, mode) ) ....
+ * Check address.
+ * Given virtual address, byte count, and rw flag
+ * returns 0 on no access.
+ * Same as useracc routine but checks for kernel access rights.
+ */
+
+_kernacc:      .globl  _kernacc
+       .word   0x4
+       clrl    r2              # r2 = 0 means kernel mode probe.
+       jbr     probes          # Dijkstra would get gastric distress here.
+
+/*
+ * addupc - increment some histogram counter
+ *     in the profiling buffer
+ *
+ * addupc(pc, prof, counts)
+ * long        pc , counts;    Only least significant word of 'counts' is added.
+ * struct      uprof *prof;
+ * 
+ * struct uprof {              # profile arguments 
+ *     short   *r_base;        # buffer base 
+ *     unsigned pr_size;       # buffer size 
+ *     unsigned pr_off;        # pc offset 
+ *     unsigned pr_scale;      # pc scaling 
+ * }
+ */
+       .globl  _addupc
+_addupc:
+       .word   4
+       movl    8(fp),r2        # r2 points to structure
+       subl3   8(r2),4(fp),r0  # r0 = PC - lowpc
+       jlss    9f              # PC < lowpc , out of range !
+       shrl    $1,r0,r0        # the unit is words
+       shrl    $1,12(r2),r1    # ditto for scale
+       emul    r1,r0,$0,r0
+       shrq    $14,r0,r0
+       tstl    r0              # too big
+       jneq    9f
+       cmpl    r1,4(r2)        # Check buffer overflow
+       jgequ   9f
+       probew  $1,*0(r2)[r1],$2        # counter accessible?
+       jeql    9f
+       shrl    $1,r1,r1        # make r1 word index
+       addw2   14(fp),*0(r2)[r1]
+9:     ret