📄 locore.s
字号:
beq a3, zero, 1f subu a2, a2, a3 # subtract from remaining count lwr v1, 0(a0) # copy 1, 2, or 3 bytes to align addu a0, a0, a3 swr v1, 0(a1) addu a1, a1, a31: and v1, a2, 3 # compute number of whole words left subu a3, a2, v1 move a2, v1 addu a3, a3, a0 # compute ending address2: lw v1, 0(a0) # copy words addu a0, a0, 4 addu a1, a1, 4 bne a0, a3, 2b sw v1, -4(a1)smallcpy: ble a2, zero, 2f addu a3, a2, a0 # compute ending address1: lbu v1, 0(a0) # copy bytes addu a0, a0, 1 addu a1, a1, 1 bne a0, a3, 1b sb v1, -1(a1)2: j ra nopEND(memcpy)/* * Copy a null terminated string within the kernel address space. * Maxlength may be null if count not wanted. * copystr(fromaddr, toaddr, maxlength, &lencopied) * caddr_t fromaddr; * caddr_t toaddr; * u_int maxlength; * u_int *lencopied; */LEAF(copystr) move t2, a2 # Save the number of bytes1: lbu t0, 0(a0) subu a2, a2, 1 beq t0, zero, 2f sb t0, 0(a1) addu a0, a0, 1 bne a2, zero, 1b addu a1, a1, 12: beq a3, zero, 3f subu a2, t2, a2 # compute length copied sw a2, 0(a3)3: j ra move v0, zeroEND(copystr)/* * Copy a null terminated string from the user address space into * the kernel address space. * * copyinstr(fromaddr, toaddr, maxlength, &lencopied) * caddr_t fromaddr; * caddr_t toaddr; * u_int maxlength; * u_int *lencopied; */NON_LEAF(copyinstr, STAND_FRAME_SIZE, ra) subu sp, sp, STAND_FRAME_SIZE .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) sw ra, STAND_RA_OFFSET(sp) blt a0, zero, copyerr # make sure address is in user space li v0, COPYERR jal copystr sw v0, UADDR+U_PCB_ONFAULT lw ra, STAND_RA_OFFSET(sp) sw zero, UADDR+U_PCB_ONFAULT addu sp, sp, STAND_FRAME_SIZE j ra move v0, zeroEND(copyinstr)/* * Copy a null terminated string from the kernel address space into * the user address space. * * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) * caddr_t fromaddr; * caddr_t toaddr; * u_int maxlength; * u_int *lencopied; */NON_LEAF(copyoutstr, STAND_FRAME_SIZE, ra) subu sp, sp, STAND_FRAME_SIZE .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) sw ra, STAND_RA_OFFSET(sp) blt a1, zero, copyerr # make sure address is in user space li v0, COPYERR jal copystr sw v0, UADDR+U_PCB_ONFAULT lw ra, STAND_RA_OFFSET(sp) sw zero, UADDR+U_PCB_ONFAULT addu sp, sp, STAND_FRAME_SIZE j ra move v0, zeroEND(copyoutstr)/* * Copy specified amount of data from user space into the kernel * copyin(from, to, len) * caddr_t *from; (user source address) * caddr_t *to; (kernel destination address) * unsigned len; */NON_LEAF(copyin, STAND_FRAME_SIZE, ra) subu sp, sp, STAND_FRAME_SIZE .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) sw ra, STAND_RA_OFFSET(sp) blt a0, zero, copyerr # make sure address is in user space li v0, COPYERR jal bcopy sw v0, UADDR+U_PCB_ONFAULT lw ra, STAND_RA_OFFSET(sp) sw zero, UADDR+U_PCB_ONFAULT addu sp, sp, STAND_FRAME_SIZE j ra move v0, zeroEND(copyin)/* * Copy specified amount of data from kernel to the user space * copyout(from, to, len) * caddr_t *from; (kernel source address) * caddr_t *to; (user destination address) * unsigned len; */NON_LEAF(copyout, STAND_FRAME_SIZE, ra) subu sp, sp, STAND_FRAME_SIZE .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) sw ra, STAND_RA_OFFSET(sp) blt a1, zero, copyerr # make sure address is in user space li v0, COPYERR jal bcopy sw v0, UADDR+U_PCB_ONFAULT lw ra, STAND_RA_OFFSET(sp) sw zero, UADDR+U_PCB_ONFAULT addu sp, sp, STAND_FRAME_SIZE j ra move v0, zeroEND(copyout)LEAF(copyerr) lw ra, STAND_RA_OFFSET(sp) sw zero, UADDR+U_PCB_ONFAULT addu sp, sp, STAND_FRAME_SIZE j ra li v0, EFAULT # return errorEND(copyerr)/* * Copy data to the DMA buffer. * The DMA bufffer can only be written one short at a time * (and takes ~14 cycles). * * CopyToBuffer(src, dst, length) * u_short *src; NOTE: must be short aligned * u_short *dst; * int length; */LEAF(CopyToBuffer) blez a2, 2f nop1: lhu t0, 0(a0) # read 2 bytes of data subu a2, a2, 2 addu a0, a0, 2 addu a1, a1, 4 bgtz a2, 1b sh t0, -4(a1) # write 2 bytes of data to buffer2: j ra nopEND(CopyToBuffer)/* * Copy data from the DMA buffer. * The DMA bufffer can only be read one short at a time * (and takes ~12 cycles). * * CopyFromBuffer(src, dst, length) * u_short *src; * char *dst; * int length; */LEAF(CopyFromBuffer) and t0, a1, 1 # test for aligned dst beq t0, zero, 3f nop blt a2, 2, 7f # at least 2 bytes to copy? nop1: lhu t0, 0(a0) # read 2 bytes of data from buffer addu a0, a0, 4 # keep buffer pointer word aligned addu a1, a1, 2 subu a2, a2, 2 sb t0, -2(a1) srl t0, t0, 8 bge a2, 2, 1b sb t0, -1(a1)3: blt a2, 2, 7f # at least 2 bytes to copy? nop6: lhu t0, 0(a0) # read 2 bytes of data from buffer addu a0, a0, 4 # keep buffer pointer word aligned addu a1, a1, 2 subu a2, a2, 2 bge a2, 2, 6b sh t0, -2(a1)7: ble a2, zero, 9f # done? nop lhu t0, 0(a0) # copy one more byte nop sb t0, 0(a1)9: j ra nopEND(CopyFromBuffer)/* * Copy the kernel stack to the new process and save the current context so * the new process will return nonzero when it is resumed by cpu_switch(). * * copykstack(up) * struct user *up; */LEAF(copykstack) subu v0, sp, UADDR # compute offset into stack addu v0, v0, a0 # v0 = new stack address move v1, sp # v1 = old stack address li t1, KERNELSTACK1: lw t0, 0(v1) # copy stack data addu v1, v1, 4 sw t0, 0(v0) bne v1, t1, 1b addu v0, v0, 4 /* FALLTHROUGH *//* * Save registers and state so we can do a longjmp later. * Note: this only works if p != curproc since * cpu_switch() will copy over pcb_context. * * savectx(up) * struct user *up; */ALEAF(savectx) sw s0, U_PCB_CONTEXT+0(a0) sw s1, U_PCB_CONTEXT+4(a0) sw s2, U_PCB_CONTEXT+8(a0) sw s3, U_PCB_CONTEXT+12(a0) mfc0 v0, MACH_COP_0_STATUS_REG sw s4, U_PCB_CONTEXT+16(a0) sw s5, U_PCB_CONTEXT+20(a0) sw s6, U_PCB_CONTEXT+24(a0) sw s7, U_PCB_CONTEXT+28(a0) sw sp, U_PCB_CONTEXT+32(a0) sw s8, U_PCB_CONTEXT+36(a0) sw ra, U_PCB_CONTEXT+40(a0) sw v0, U_PCB_CONTEXT+44(a0) j ra move v0, zeroEND(copykstack)/* * The following primitives manipulate the run queues. _whichqs tells which * of the 32 queues _qs have processes in them. Setrunqueue 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_priority, divided * by 4 actually to shrink the 0-127 range of priorities into the 32 available * queues. *//* * setrunqueue(p) * proc *p; * * Call should be made at splclock(), and p->p_stat should be SRUN. */NON_LEAF(setrunqueue, STAND_FRAME_SIZE, ra) subu sp, sp, STAND_FRAME_SIZE .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) lw t0, P_BACK(a0) ## firewall: p->p_back must be 0 sw ra, STAND_RA_OFFSET(sp) ## beq t0, zero, 1f ## lbu t0, P_PRIORITY(a0) # put on p->p_priority / 4 queue PANIC("setrunqueue") ##1: li t1, 1 # compute corresponding bit srl t0, t0, 2 # compute index into 'whichqs' sll t1, t1, t0 lw t2, whichqs # set corresponding bit nop or t2, t2, t1 sw t2, whichqs sll t0, t0, 3 # compute index into 'qs' la t1, qs addu t0, t0, t1 # t0 = qp = &qs[pri >> 2] lw t1, P_BACK(t0) # t1 = qp->ph_rlink sw t0, P_FORW(a0) # p->p_forw = qp sw t1, P_BACK(a0) # p->p_back = qp->ph_rlink sw a0, P_FORW(t1) # p->p_back->p_forw = p; sw a0, P_BACK(t0) # qp->ph_rlink = p j ra addu sp, sp, STAND_FRAME_SIZEEND(setrunqueue)/* * Remrq(p) * * Call should be made at splclock(). */NON_LEAF(remrq, STAND_FRAME_SIZE, ra) subu sp, sp, STAND_FRAME_SIZE .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) lbu t0, P_PRIORITY(a0) # get from p->p_priority / 4 queue li t1, 1 # compute corresponding bit srl t0, t0, 2 # compute index into 'whichqs' lw t2, whichqs # check corresponding bit sll t1, t1, t0 and v0, t2, t1 sw ra, STAND_RA_OFFSET(sp) ## bne v0, zero, 1f ## lw v0, P_BACK(a0) # v0 = p->p_back PANIC("remrq") ## it wasnt recorded to be on its q1: lw v1, P_FORW(a0) # v1 = p->p_forw nop sw v1, P_FORW(v0) # p->p_back->p_forw = p->p_forw; sw v0, P_BACK(v1) # p->p_forw->p_back = p->r_rlink sll t0, t0, 3 # compute index into 'qs' la v0, qs addu t0, t0, v0 # t0 = qp = &qs[pri >> 2] lw v0, P_FORW(t0) # check if queue empty nop bne v0, t0, 2f # No. qp->ph_link != qp nop xor t2, t2, t1 # clear corresponding bit in 'whichqs' sw t2, whichqs2: sw zero, P_BACK(a0) ## for firewall checking j ra addu sp, sp, STAND_FRAME_SIZEEND(remrq)/* * switch_exit() * * At exit of a process, do a cpu_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. * All interrupts should be blocked at this point. */LEAF(switch_exit) la v1, nullproc # save state into garbage proc lw t0, P_UPTE+0(v1) # t0 = first u. pte lw t1, P_UPTE+4(v1) # t1 = 2nd u. pte li v0, UADDR # v0 = first HI entry mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register mtc0 v0, MACH_COP_0_TLB_HI # init high entry mtc0 t0, MACH_COP_0_TLB_LOW # init low entry li t0, 1 << VMMACH_TLB_INDEX_SHIFT tlbwi # Write the TLB entry. addu v0, v0, NBPG # 2nd HI entry mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register mtc0 v0, MACH_COP_0_TLB_HI # init high entry mtc0 t1, MACH_COP_0_TLB_LOW # init low entry sw zero, curproc tlbwi # Write the TLB entry. b cpu_switch li sp, KERNELSTACK - START_FRAME # switch to standard stackEND(switch_exit)/* * When no processes are on the runq, cpu_switch branches to idle * to wait for something to come ready. * Note: this is really a part of cpu_switch() but defined here for kernel * profiling. */LEAF(idle) li t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts sw zero, curproc # set curproc NULL for stats1: lw t0, whichqs # look for non-empty queue nop beq t0, zero, 1b nop b sw1 mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interruptsEND(idle)/* * cpu_switch() * Find the highest priority process and resume it. */NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra) sw sp, UADDR+U_PCB_CONTEXT+32 # save old sp subu sp, sp, STAND_FRAME_SIZE sw ra, STAND_RA_OFFSET(sp) .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) lw t2, cnt+V_SWTCH # for statistics lw t1, whichqs # look for non-empty queue sw s0, UADDR+U_PCB_CONTEXT+0 # do a 'savectx()' sw s1, UADDR+U_PCB_CONTEXT+4 sw s2, UADDR+U_PCB_CONTEXT+8 sw s3, UADDR+U_PCB_CONTEXT+12 mfc0 t0, MACH_COP_0_STATUS_REG # t0 = saved status register sw s4, UADDR+U_PCB_CONTEXT+16 sw s5, UADDR+U_PCB_CONTEXT+20 sw s6, UADDR+U_PCB_CONTEXT+24 sw s7, UADDR+U_PCB_CONTEXT+28 sw s8, UADDR+U_PCB_CONTEXT+36 sw ra, UADDR+U_PCB_CONTEXT+40 # save return address sw t0, UADDR+U_PCB_CONTEXT+44 # save status register addu t2, t2, 1 sw t2, cnt+V_SWTCH beq t1, zero, idle # if none, idle mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interruptssw1: nop # wait for intrs disabled nop lw t0, whichqs # look for non-empty queue li t2, -1 # t2 = lowest bit set beq t0, zero, idle # if none, idle move t3, t0 # t3 = saved whichqs1: addu t2, t2, 1 and t1, t0, 1 # bit set? beq t1, zero, 1b srl t0, t0, 1 # try next bit/* * Remove process from queue. */ sll t0, t2, 3 la t1, qs addu t0, t0, t1 # t0 = qp = &qs[highbit] lw a0, P_FORW(t0) # a0 = p = highest pri process nop lw v0, P_FORW(a0) # v0 = p->p_forw bne t0, a0, 2f # make sure something in queue sw v0, P_FORW(t0) # qp->ph_link = p->p_forw; PANIC("cpu_switch") # nothing in queue2: sw t0, P_BACK(v0) # p->p_forw->p_back = qp bne v0, t0, 3f # queue still not empty sw zero, P_BACK(a0) ## for firewall checking li v1, 1 # compute bit in 'whichqs' sll v1, v1, t2 xor t3, t3, v1 # clear bit in 'whichqs' sw t3, whichqs3:/* * Switch to new context. */ sw zero, want_resched jal pmap_alloc_tlbpid # v0 = TLB PID move s0, a0 # BDSLOT: save p sw s0, curproc # set curproc sll v0, v0, VMMACH_TLB_PID_SHIFT # v0 = aligned PID lw t0, P_UPTE+0(s0) # t0 = first u. pte lw t1, P_UPTE+4(s0) # t1 = 2nd u. pte or v0, v0, UADDR # v0 = first HI entry/* * Resume process indicated by the pte's for its u struct * NOTE: This is hard coded to UPAGES == 2. * Also, there should be no TLB faults at this point. */ mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register mtc0 v0, MACH_COP_0_TLB_HI # init high entry mtc0 t0, MACH_COP_0_TLB_LOW # init low entry li t0, 1 << VMMACH_TLB_INDEX_SHIFT tlbwi # Write the TLB entry. addu v0, v0, NBPG # 2nd HI entry mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register mtc0 v0, MACH_COP_0_TLB_HI # init high entry mtc0 t1, MACH_COP_0_TLB_LOW # init low entry nop tlbwi # Write the TLB entry.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -