📄 locore.s
字号:
* Call should be made at spl6(), and p->p_stat should be SRUN */ENTRY(setrunqueue) movl sp@(4),a0 tstl a0@(P_BACK) jeq Lset1 movl #Lset2,sp@- jbsr _panicLset1: clrl d0 movb a0@(P_PRIORITY),d0 lsrb #2,d0 movl _whichqs,d1 bset d0,d1 movl d1,_whichqs lslb #3,d0 addl #_qs,d0 movl d0,a0@(P_FORW) movl d0,a1 movl a1@(P_BACK),a0@(P_BACK) movl a0,a1@(P_BACK) movl a0@(P_BACK),a1 movl a0,a1@(P_FORW) rtsLset2: .asciz "setrunqueue" .even/* * Remrq(p) * * Call should be made at spl6(). */ENTRY(remrq) movl sp@(4),a0 clrl d0 movb a0@(P_PRIORITY),d0 lsrb #2,d0 movl _whichqs,d1 bclr d0,d1 jne Lrem1 movl #Lrem3,sp@- jbsr _panicLrem1: movl d1,_whichqs movl a0@(P_FORW),a1 movl a0@(P_BACK),a1@(P_BACK) movl a0@(P_BACK),a1 movl a0@(P_FORW),a1@(P_FORW) movl #_qs,a1 movl d0,d1 lslb #3,d1 addl d1,a1 cmpl a1@(P_FORW),a1 jeq Lrem2 movl _whichqs,d1 bset d0,d1 movl d1,_whichqsLrem2: clrl a0@(P_BACK) rtsLrem3: .asciz "remrq"Lsw0: .asciz "switch" .even .globl _curpcb .globl _masterpaddr | XXX compatibility (debuggers) .data_masterpaddr: | XXX compatibility (debuggers)_curpcb: .long 0mdpflag: .byte 0 | copy of proc md_flags low byte .align 2 .comm nullpcb,SIZEOF_PCB .text/* * At exit of a process, do a switch for the last time. * The mapping of the pcb at p->p_addr has already been deleted, * and the memory for the pcb+stack has been freed. * The ipl is high enough to prevent the memory from being reallocated. */ENTRY(switch_exit) movl #nullpcb,_curpcb | save state into garbage pcb lea tmpstk,sp | goto a tmp stack jra _cpu_switch/* * When no processes are on the runq, Swtch branches to Idle * to wait for something to come ready. */ .globl idleidle: stop #PSL_LOWIPLIdle: movw #PSL_HIGHIPL,sr tstl _whichqs jeq idle movw #PSL_LOWIPL,sr jra Lsw1Lbadsw: movl #Lsw0,sp@- jbsr _panic /*NOTREACHED*//* * cpu_switch() * * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the * entire ATC. The effort involved in selective flushing may not be * worth it, maybe we should just flush the whole thing? * * NOTE 2: With the new VM layout we now no longer know if an inactive * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag * bit). For now, we just always flush the full ATC. */ENTRY(cpu_switch) movl _curpcb,a0 | current pcb movw sr,a0@(PCB_PS) | save sr before changing ipl#ifdef notyet movl _curproc,sp@- | remember last proc running#endif clrl _curproc addql #1,_cnt+V_SWTCHLsw1: /* * Find the highest-priority queue that isn't empty, * then take the first proc from that queue. */ clrl d0 lea _whichqs,a0 movl a0@,d1Lswchk: btst d0,d1 jne Lswfnd addqb #1,d0 cmpb #32,d0 jne Lswchk jra IdleLswfnd: movw #PSL_HIGHIPL,sr | lock out interrupts movl a0@,d1 | and check again... bclr d0,d1 jeq Lsw1 | proc moved, rescan movl d1,a0@ | update whichqs moveq #1,d1 | double check for higher priority lsll d0,d1 | process (which may have snuck in subql #1,d1 | while we were finding this one) andl a0@,d1 jeq Lswok | no one got in, continue movl a0@,d1 bset d0,d1 | otherwise put this one back movl d1,a0@ jra Lsw1 | and rescanLswok: movl d0,d1 lslb #3,d1 | convert queue number to index addl #_qs,d1 | locate queue (q) movl d1,a1 cmpl a1@(P_FORW),a1 | anyone on queue? jeq Lbadsw | no, panic movl a1@(P_FORW),a0 | p = q->p_forw movl a0@(P_FORW),a1@(P_FORW) | q->p_forw = p->p_forw movl a0@(P_FORW),a1 | q = p->p_forw movl a0@(P_BACK),a1@(P_BACK) | q->p_back = p->p_back cmpl a0@(P_FORW),d1 | anyone left on queue? jeq Lsw2 | no, skip movl _whichqs,d1 bset d0,d1 | yes, reset bit movl d1,_whichqsLsw2: movl a0,_curproc clrl _want_resched#ifdef notyet movl sp@+,a1 cmpl a0,a1 | switching to same proc? jeq Lswdone | yes, skip save and restore#endif /* * Save state of previous process in its pcb. */ movl _curpcb,a1 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers movl usp,a2 | grab USP (a2 has been saved) movl a2,a1@(PCB_USP) | and save it#ifdef FPCOPROC lea a1@(PCB_FPCTX),a2 | pointer to FP save area fsave a2@ | save FP state tstb a2@ | null state frame? jeq Lswnofpsave | yes, all done fmovem fp0-fp7,a2@(216) | save FP general registers fmovem fpcr/fpsr/fpi,a2@(312) | save FP control registersLswnofpsave:#endif#ifdef DIAGNOSTIC tstl a0@(P_WCHAN) jne Lbadsw cmpb #SRUN,a0@(P_STAT) jne Lbadsw#endif clrl a0@(P_BACK) | clear back link movb a0@(P_MDFLAG+3),mdpflag | low byte of p_md.md_flags movl a0@(P_ADDR),a1 | get p_addr movl a1,_curpcb /* see if pmap_activate needs to be called; should remove this */ movl a0@(P_VMSPACE),a0 | vmspace = p->p_vmspace#ifdef DIAGNOSTIC tstl a0 | map == VM_MAP_NULL? jeq Lbadsw | panic#endif lea a0@(VM_PMAP),a0 | pmap = &vmspace.vm_pmap tstl a0@(PM_STCHG) | pmap->st_changed? jeq Lswnochg | no, skip pea a1@ | push pcb (at p_addr) pea a0@ | push pmap jbsr _pmap_activate | pmap_activate(pmap, pcb) addql #8,sp movl _curpcb,a1 | restore p_addrLswnochg: movl #PGSHIFT,d1 movl a1,d0 lsrl d1,d0 | convert p_addr to page number lsll #2,d0 | and now to Sysmap offset addl _Sysmap,d0 | add Sysmap base to get PTE addr#ifdef notdef movw #PSL_HIGHIPL,sr | go crit while changing PTEs#endif lea tmpstk,sp | now goto a tmp stack for NMI movl d0,a0 | address of new context movl _Umap,a2 | address of PTEs for kstack moveq #UPAGES-1,d0 | sizeof kstackLres1: movl a0@+,d1 | get PTE andl #~PG_PROT,d1 | mask out old protection orl #PG_RW+PG_V,d1 | ensure valid and writable movl d1,a2@+ | load it up dbf d0,Lres1 | til done#if defined(HP380) cmpl #-2,_mmutype | 68040? jne Lres1a | no, skip .word 0xf518 | yes, pflusha movl a1@(PCB_USTP),d0 | get USTP moveq #PGSHIFT,d1 lsll d1,d0 | convert to addr .long 0x4e7b0806 | movc d0,urp jra LcxswdoneLres1a:#endif movl #CACHE_CLR,d0 movc d0,cacr | invalidate cache(s)#if defined(HP330) || defined(HP360) || defined(HP370) tstl _mmutype | HP MMU? jeq Lhpmmu4 | yes, skip pflusha | flush entire TLB movl a1@(PCB_USTP),d0 | get USTP moveq #PGSHIFT,d1 lsll d1,d0 | convert to addr lea _protorp,a0 | CRP prototype movl d0,a0@(4) | stash USTP pmove a0@,crp | load new user root pointer jra Lcxswdone | thats itLhpmmu4: #endif#if defined(HP320) || defined(HP350) MMUADDR(a0) movl a0@(MMUTBINVAL),d1 | invalidate TLB tstl _ectype | got external VAC? jle Lnocache1 | no, skip andl #~MMU_CEN,a0@(MMUCMD) | toggle cache enable orl #MMU_CEN,a0@(MMUCMD) | to clear data cacheLnocache1: movl a1@(PCB_USTP),a0@(MMUUSTP) | context switch#endifLcxswdone: moveml a1@(PCB_REGS),#0xFCFC | and registers movl a1@(PCB_USP),a0 movl a0,usp | and USP#ifdef FPCOPROC lea a1@(PCB_FPCTX),a0 | pointer to FP save area tstb a0@ | null state frame? jeq Lresfprest | yes, easy#if defined(HP380) cmpl #-2,_mmutype | 68040? jne Lresnot040 | no, skip clrl sp@- | yes... frestore sp@+ | ...magic!Lresnot040:#endif fmovem a0@(312),fpcr/fpsr/fpi | restore FP control registers fmovem a0@(216),fp0-fp7 | restore FP general registersLresfprest: frestore a0@ | restore state#endif movw a1@(PCB_PS),sr | no, restore PS moveq #1,d0 | return 1 (for alternate returns) rts/* * savectx(pcb, altreturn) * Update pcb, saving current processor state and arranging * for alternate return ala longjmp in switch if altreturn is true. */ENTRY(savectx) movl sp@(4),a1 movw sr,a1@(PCB_PS) movl usp,a0 | grab USP movl a0,a1@(PCB_USP) | and save it moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers#ifdef FPCOPROC lea a1@(PCB_FPCTX),a0 | pointer to FP save area fsave a0@ | save FP state tstb a0@ | null state frame? jeq Lsvnofpsave | yes, all done fmovem fp0-fp7,a0@(216) | save FP general registers fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registersLsvnofpsave:#endif tstl sp@(8) | altreturn? jeq Lsavedone movl sp,d0 | relocate current sp relative to a1 subl #_kstack,d0 | (sp is relative to kstack): addl d0,a1 | a1 += sp - kstack; movl sp@,a1@ | write return pc at (relocated) sp@Lsavedone: moveq #0,d0 | return 0 rts/* * {fu,su},{byte,sword,word} */ALTENTRY(fuiword, _fuword)ENTRY(fuword) movl sp@(4),a0 | address to read movl _curpcb,a1 | current pcb movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault movsl a0@,d0 | do read from user space nop jra LfsdoneENTRY(fusword) movl sp@(4),a0 movl _curpcb,a1 | current pcb movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault moveq #0,d0 movsw a0@,d0 | do read from user space nop jra Lfsdone/* Just like fusword, but tells trap code not to page in. */ENTRY(fuswintr) movl sp@(4),a0 movl _curpcb,a1 movl #_fswintr,a1@(PCB_ONFAULT) moveq #0,d0 movsw a0@,d0 nop jra LfsdoneALTENTRY(fuibyte, _fubyte)ENTRY(fubyte) movl sp@(4),a0 | address to read movl _curpcb,a1 | current pcb movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault moveq #0,d0 movsb a0@,d0 | do read from user space nop jra LfsdoneLfserr: moveq #-1,d0 | error indicatorLfsdone: clrl a1@(PCB_ONFAULT) | clear fault address rts/* Just like Lfserr, but the address is different (& exported). */ .globl _fswintr_fswintr: moveq #-1,d0 jra Lfsdone/* * Write a longword in user instruction space. * Largely the same as suword but with a final i-cache purge on those * machines with split caches. */ENTRY(suiword) movl sp@(4),a0 | address to write movl sp@(8),d0 | value to put there movl _curpcb,a1 | current pcb movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault movsl d0,a0@ | do write to user space nop moveq #0,d0 | indicate no fault#if defined(HP380) cmpl #-2,_mmutype | 68040? jne Lsuicpurge | no, skip .word 0xf498 | cinva ic (XXX overkill) jra LfsdoneLsuicpurge:#endif movl #IC_CLEAR,d1 movc d1,cacr | invalidate i-cache jra LfsdoneENTRY(suword) movl sp@(4),a0 | address to write movl sp@(8),d0 | value to put there movl _curpcb,a1 | current pcb movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault movsl d0,a0@ | do write to user space nop moveq #0,d0 | indicate no fault jra LfsdoneENTRY(susword) movl sp@(4),a0 | address to write movw sp@(10),d0 | value to put there movl _curpcb,a1 | current pcb movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault movsw d0,a0@ | do write to user space nop moveq #0,d0 | indicate no fault jra LfsdoneENTRY(suswintr) movl sp@(4),a0 movw sp@(10),d0 movl _curpcb,a1 movl #_fswintr,a1@(PCB_ONFAULT) movsw d0,a0@ nop moveq #0,d0 jra LfsdoneALTENTRY(suibyte, _subyte)ENTRY(subyte) movl sp@(4),a0 | address to write movb sp@(11),d0 | value to put there movl _curpcb,a1 | current pcb movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault movsb d0,a0@ | do write to user space nop moveq #0,d0 | indicate no fault jra Lfsdone#if defined(HP380)ENTRY(suline) movl sp@(4),a0 | address to write movl _curpcb,a1 | current pcb movl #Lslerr,a1@(PCB_ONFAULT) | where to return to on a fault movl sp@(8),a1 | address of line movl a1@+,d0 | get lword movsl d0,a0@+ | put lword nop | sync movl a1@+,d0 | get lword movsl d0,a0@+ | put lword nop | sync movl a1@+,d0 | get lword movsl d0,a0@+ | put lword nop | sync movl a1@+,d0 | get lword movsl d0,a0@+ | put lword nop | sync moveq #0,d0 | indicate no fault jra LsldoneLslerr: moveq #-1,d0Lsldone: movl _curpcb,a1 | current pcb clrl a1@(PCB_ONFAULT) | clear fault address rts#endif/* * Invalidate entire TLB. */ENTRY(TBIA)__TBIA:#if defined(HP380) cmpl #-2,_mmutype | 68040? jne Lmotommu3 | no, skip .word 0xf518 | yes, pflusha rtsLmotommu3:#endif#if defined(HP330) || defined(HP360) || defined(HP370) tstl _mmutype | HP MMU? jeq Lhpmmu6 | yes, skip
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -