📄 locore.s
字号:
set1: movzbl P_PRIORITY(%eax),%edx shrl $2,%edx btsl %edx,_whichqs # set q full bit shll $3,%edx addl $_qs,%edx # locate q hdr movl %edx,P_FORW(%eax) # link process on tail of q movl P_BACK(%edx),%ecx movl %ecx,P_BACK(%eax) movl %eax,P_BACK(%edx) movl %eax,P_FORW(%ecx) retset2: .asciz "setrunqueue"/* * Remrq(p) * * Call should be made at spl6(). */ ALIGN32ENTRY(remrq) movl 4(%esp),%eax movzbl P_PRIORITY(%eax),%edx shrl $2,%edx btrl %edx,_whichqs # clear full bit, panic if clear already jb rem1 pushl $rem3 call _panicrem1: pushl %edx movl P_FORW(%eax),%ecx # unlink process movl P_BACK(%eax),%edx movl %edx,P_BACK(%ecx) movl P_BACK(%eax),%ecx movl P_FORW(%eax),%edx movl %edx,P_FORW(%ecx) popl %edx movl $_qs,%ecx shll $3,%edx addl %edx,%ecx cmpl P_FORW(%ecx),%ecx # q still has something? je rem2 shrl $3,%edx # yes, set bit as still full btsl %edx,_whichqsrem2: movl $0,P_BACK(%eax) # zap reverse link to indicate off list retrem3: .asciz "remrq"sw0: .asciz "Xswitch"/* * When no processes are on the runq, Swtch branches to idle * to wait for something to come ready. */ .globl Idle ALIGN32Idle:idle: call _spl0 cmpl $0,_whichqs jne sw1 hlt # wait for interrupt jmp idle .align 4 /* ..so that profiling doesn't lump Idle with Xswitch().. */badsw: pushl $sw0 call _panic /*NOTREACHED*//* * Swtch() */ ALIGN32ENTRY(Xswitch) incl _cnt+V_SWTCH /* switch to new process. first, save context as needed */ movl _curproc,%ecx /* if no process to save, don't bother */ cmpl $0,%ecx je sw1 movl P_ADDR(%ecx),%ecx movl (%esp),%eax # Hardware registers movl %eax, PCB_EIP(%ecx) movl %ebx, PCB_EBX(%ecx) movl %esp, PCB_ESP(%ecx) movl %ebp, PCB_EBP(%ecx) movl %esi, PCB_ESI(%ecx) movl %edi, PCB_EDI(%ecx)#ifdef NPX /* have we used fp, and need a save? */ mov _curproc,%eax cmp %eax,_npxproc jne 1f pushl %ecx /* h/w bugs make saving complicated */ leal PCB_SAVEFPU(%ecx),%eax pushl %eax call _npxsave /* do it in a big C function */ popl %eax popl %ecx1:#endif movl _CMAP2,%eax # save temporary map PTE movl %eax,PCB_CMAP2(%ecx) # in our context movl $0,_curproc # out of process # movw _cpl, %ax # movw %ax, PCB_IML(%ecx) # save ipl /* save is done, now choose a new process or idle */sw1: movl _whichqs,%edi2: cli bsfl %edi,%eax # find a full q jz idle # if none, idle # XX update whichqs?swfnd: btrl %eax,%edi # clear q full status jnb 2b # if it was clear, look for another movl %eax,%ebx # save which one we are using shll $3,%eax addl $_qs,%eax # select q movl %eax,%esi#ifdef DIAGNOSTIC cmpl P_FORW(%eax),%eax # linked to self? (e.g. not on list) je badsw # not possible#endif movl P_FORW(%eax),%ecx # unlink from front of process q movl P_FORW(%ecx),%edx movl %edx,P_FORW(%eax) movl P_BACK(%ecx),%eax movl %eax,P_BACK(%edx) cmpl P_FORW(%ecx),%esi # q empty je 3f btsl %ebx,%edi # nope, set to indicate full3: movl %edi,_whichqs # update q status movl $0,%eax movl %eax,_want_resched#ifdef DIAGNOSTIC cmpl %eax,P_WCHAN(%ecx) jne badsw cmpb $ SRUN,P_STAT(%ecx) jne badsw#endif movl %eax,P_BACK(%ecx) /* isolate process to run */ movl P_ADDR(%ecx),%edx movl PCB_CR3(%edx),%ebx /* switch address space */ movl %ebx,%cr3 /* restore context */ movl PCB_EBX(%edx), %ebx movl PCB_ESP(%edx), %esp movl PCB_EBP(%edx), %ebp movl PCB_ESI(%edx), %esi movl PCB_EDI(%edx), %edi movl PCB_EIP(%edx), %eax movl %eax, (%esp) movl PCB_CMAP2(%edx),%eax # get temporary map movl %eax,_CMAP2 # reload temporary map PTE movl %ecx,_curproc # into next process movl %edx,_curpcb /* pushl PCB_IML(%edx) call _splx popl %eax*/ movl %edx,%eax # return (1); ret .globl _mvesp ALIGN32_mvesp: movl %esp,%eax ret/* * struct proc *switch_to_inactive(p) ; struct proc *p; * * At exit of a process, move off the address space of the * process and onto a "safe" one. Then, on a temporary stack * return and run code that disposes of the old state. * Since this code requires a parameter from the "old" stack, * pass it back as a return value. */ ALIGN32ENTRY(switch_to_inactive) popl %edx # old pc popl %eax # arg, our return value movl _IdlePTD,%ecx movl %ecx,%cr3 # good bye address space #write buffer? movl $tmpstk-4,%esp # temporary stack, compensated for call jmp %edx # return, execute remainder of cleanup/* * savectx(pcb, altreturn) * Update pcb, saving current processor state and arranging * for alternate return ala longjmp in Xswitch if altreturn is true. */ ALIGN32ENTRY(savectx) movl 4(%esp), %ecx movw _cpl, %ax movw %ax, PCB_IML(%ecx) movl (%esp), %eax movl %eax, PCB_EIP(%ecx) movl %ebx, PCB_EBX(%ecx) movl %esp, PCB_ESP(%ecx) movl %ebp, PCB_EBP(%ecx) movl %esi, PCB_ESI(%ecx) movl %edi, PCB_EDI(%ecx)#ifdef NPX /* * If npxproc == NULL, then the npx h/w state is irrelevant and the * state had better already be in the pcb. This is true for forks * but not for dumps (the old book-keeping with FP flags in the pcb * always lost for dumps because the dump pcb has 0 flags). * * If npxproc != NULL, then we have to save the npx h/w state to * npxproc's pcb and copy it to the requested pcb, or save to the * requested pcb and reload. Copying is easier because we would * have to handle h/w bugs for reloading. We used to lose the * parent's npx state for forks by forgetting to reload. */ mov _npxproc,%eax testl %eax,%eax je 1f pushl %ecx movl P_ADDR(%eax),%eax leal PCB_SAVEFPU(%eax),%eax pushl %eax pushl %eax call _npxsave popl %eax popl %eax popl %ecx pushl %ecx pushl $108+8*2 /* XXX h/w state size + padding */ leal PCB_SAVEFPU(%ecx),%ecx pushl %ecx pushl %eax call _bcopy addl $12,%esp popl %ecx1:#endif movl _CMAP2, %edx # save temporary map PTE movl %edx, PCB_CMAP2(%ecx) # in our context cmpl $0, 8(%esp) je 1f movl %esp, %edx # relocate current sp relative to pcb subl $_kstack, %edx # (sp is relative to kstack): addl %edx, %ecx # pcb += sp - kstack; movl %eax, (%ecx) # write return pc at (relocated) sp@ # this mess deals with replicating register state gcc hides movl 12(%esp),%eax movl %eax,12(%ecx) movl 16(%esp),%eax movl %eax,16(%ecx) movl 20(%esp),%eax movl %eax,20(%ecx) movl 24(%esp),%eax movl %eax,24(%ecx)1: xorl %eax, %eax # return 0 ret/* * addupc(int pc, struct uprof *up, int ticks): * update profiling information for the user process. */ ALIGN32ENTRY(addupc) pushl %ebp movl %esp,%ebp movl 12(%ebp),%edx /* up */ movl 8(%ebp),%eax /* pc */ subl PR_OFF(%edx),%eax /* pc -= up->pr_off */ jl L1 /* if (pc < 0) return */ shrl $1,%eax /* praddr = pc >> 1 */ imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */ shrl $15,%eax /* praddr = praddr << 15 */ andl $-2,%eax /* praddr &= ~1 */ cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */ ja L1/* addl %eax,%eax /* praddr -> word offset */ addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */ movl 16(%ebp),%ecx /* ticks */ movl _curpcb,%edx movl $proffault,PCB_ONFAULT(%edx) addl %ecx,(%eax) /* storage location += ticks */ movl $0,PCB_ONFAULT(%edx)L1: leave ret ALIGN32proffault: /* if we get a fault, then kill profiling all together */ movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */ movl 12(%ebp),%ecx movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */ leave ret.data ALIGN32 .globl _cyloffset, _curpcb_cyloffset: .long 0 .globl _proc0paddr_proc0paddr: .long 0LF: .asciz "Xswitch %x".text # To be done: .globl _astoff_astoff: ret#define IDTVEC(name) .align 4; .globl _X/**/name; _X/**/name:#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ call _panic; 1: .asciz msg#define PRINTF(n,msg) pushal ; nop ; pushl 1f; call _printf; MSG(msg) ; \ popl %eax ; popal#define MSG(msg) .data; 1: .asciz msg; .text .text/* * Trap and fault vector routines */ #define TRAP(a) pushl $(a) ; jmp alltraps#ifdef KGDB#define BPTTRAP(a) pushl $(a) ; jmp bpttraps#else#define BPTTRAP(a) TRAP(a)#endifIDTVEC(div) pushl $0; TRAP(T_DIVIDE)IDTVEC(dbg) pushl $0; BPTTRAP(T_TRCTRAP)IDTVEC(nmi) pushl $0; TRAP(T_NMI)IDTVEC(bpt) pushl $0; BPTTRAP(T_BPTFLT)IDTVEC(ofl) pushl $0; TRAP(T_OFLOW)IDTVEC(bnd) pushl $0; TRAP(T_BOUND)IDTVEC(ill) pushl $0; TRAP(T_PRIVINFLT)IDTVEC(dna) pushl $0; TRAP(T_DNA)IDTVEC(dble) TRAP(T_DOUBLEFLT) /*PANIC("Double Fault");*/IDTVEC(fpusegm) pushl $0; TRAP(T_FPOPFLT)IDTVEC(tss) TRAP(T_TSSFLT) /*PANIC("TSS not valid");*/IDTVEC(missing) TRAP(T_SEGNPFLT)IDTVEC(stk) TRAP(T_STKFLT)IDTVEC(prot) TRAP(T_PROTFLT)IDTVEC(page) TRAP(T_PAGEFLT)IDTVEC(rsvd) pushl $0; TRAP(T_RESERVED)IDTVEC(fpu)#ifdef NPX /* * Handle like an interrupt so that we can call npxintr to clear the * error. It would be better to handle npx interrupts as traps but * this is difficult for nested interrupts. */ pushl $0 /* dummy error code */ pushl $T_ASTFLT pushal nop /* silly, the bug is for popal and it only * bites when the next instruction has a * complicated address mode */ pushl %ds pushl %es /* now the stack frame is a trap frame */ movl $KDSEL,%eax movl %ax,%ds movl %ax,%es pushl _cpl pushl $0 /* dummy unit to finish building intr frame */ incl _cnt+V_TRAP call _npxintr jmp doreti#else pushl $0; TRAP(T_ARITHTRAP)#endif /* 17 - 31 reserved for future exp */IDTVEC(rsvd0) pushl $0; TRAP(17)IDTVEC(rsvd1) pushl $0; TRAP(18)IDTVEC(rsvd2) pushl $0; TRAP(19)IDTVEC(rsvd3) pushl $0; TRAP(20)IDTVEC(rsvd4) pushl $0; TRAP(21)IDTVEC(rsvd5) pushl $0; TRAP(22)IDTVEC(rsvd6) pushl $0; TRAP(23)IDTVEC(rsvd7) pushl $0; TRAP(24)IDTVEC(rsvd8) pushl $0; TRAP(25)IDTVEC(rsvd9) pushl $0; TRAP(26)IDTVEC(rsvd10) pushl $0; TRAP(27)IDTVEC(rsvd11) pushl $0; TRAP(28)IDTVEC(rsvd12) pushl $0; TRAP(29)IDTVEC(rsvd13) pushl $0; TRAP(30)IDTVEC(rsvd14) pushl $0; TRAP(31) ALIGN32alltraps: pushal nop push %ds push %es # movw $KDSEL,%ax movw $0x10,%ax movw %ax,%ds movw %ax,%escalltrap: incl _cnt+V_TRAP call _trap /* * Return through doreti to handle ASTs. Have to change trap frame * to interrupt frame. */ movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */ pushl _cpl pushl $0 /* dummy unit */ jmp doreti#ifdef KGDB/* * This code checks for a kgdb trap, then falls through * to the regular trap code. */ ALIGN32bpttraps: pushal nop push %es push %ds # movw $KDSEL,%ax movw $0x10,%ax movw %ax,%ds movw %ax,%es movzwl 52(%esp),%eax test $3,%eax jne calltrap call _kgdb_trap_glue jmp calltrap#endif/* * Call gate entry for syscall */ ALIGN32IDTVEC(syscall) pushfl # only for stupid carry bit and more stupid wait3 cc kludge pushal # only need eax,ecx,edx - trap resaves others nop movl $KDSEL,%eax # switch to kernel segments movl %ax,%ds movl %ax,%es incl _cnt+V_SYSCALL # kml 3/25/93 call _syscall /* * Return through doreti to handle ASTs. Have to change syscall frame * to interrupt frame. * * XXX - we should have set up the frame earlier to avoid the * following popal/pushal (not much can be done to avoid shuffling * the flags). Consistent frames would simplify things all over. */ movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */ movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */ movl 32+8(%esp),%ecx movl %ebx,32+0(%esp) movl %ecx,32+4(%esp) movl %eax,32+8(%esp) popal nop pushl $0 /* dummy error code */ pushl $T_ASTFLT pushal nop movl __udatasel,%eax /* switch back to user segments */ push %eax /* XXX - better to preserve originals? */ push %eax pushl _cpl pushl $0 jmp doreti ALIGN32ENTRY(htonl)ENTRY(ntohl) movl 4(%esp),%eax xchgb %al,%ah roll $16,%eax xchgb %al,%ah ret ALIGN32ENTRY(htons)ENTRY(ntohs) movzwl 4(%esp),%eax xchgb %al,%ah ret#include "vector.s"#include "i386/isa/icu.s"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -