📄 locore.s
字号:
.set reorderEND(bcmp)/* * {ov}bcopy(from, to, len) */LEAF(bcopy)ALEAF(ovbcopy) .set noreorder addu t0, a0, a2 # t0 = end of s1 region sltu t1, a1, t0 sltu t2, a0, a1 and t1, t1, t2 # t1 = true if from < to < (from+len) beq t1, zero, forward # non overlapping, do forward copy slt t2, a2, 12 # check for small copy ble a2, zero, 2f addu t1, a1, a2 # t1 = end of to region1: lb v0, -1(t0) # copy bytes backwards, subu t0, t0, 1 # doesn't happen often so do slow way subu t1, t1, 1 bne t0, a0, 1b sb v0, 0(t1)2: j ra nopforward: bne t2, zero, smallcpy # do a small bcopy xor v0, a0, a1 # compare low two bits of addresses and v0, v0, 3 subu a3, zero, a1 # compute # bytes to word align address beq v0, zero, aligned # addresses can be word aligned and a3, a3, 3 beq a3, zero, 1f subu a2, a2, a3 # subtract from remaining count LWHI v0, 0(a0) # get next 4 bytes (unaligned) LWLO v0, 3(a0) addu a0, a0, a3 SWHI v0, 0(a1) # store 1, 2, or 3 bytes to align a1 addu a1, a1, a31: and v0, a2, 3 # compute number of words left subu a3, a2, v0 move a2, v0 addu a3, a3, a0 # compute ending address2: LWHI v0, 0(a0) # copy words a0 unaligned, a1 aligned LWLO v0, 3(a0) addu a0, a0, 4 addu a1, a1, 4 bne a0, a3, 2b sw v0, -4(a1) b smallcpy nopaligned: beq a3, zero, 1f subu a2, a2, a3 # subtract from remaining count LWHI v0, 0(a0) # copy 1, 2, or 3 bytes to align addu a0, a0, a3 SWHI v0, 0(a1) addu a1, a1, a31: and v0, a2, 3 # compute number of whole words left subu a3, a2, v0 move a2, v0 addu a3, a3, a0 # compute ending address2: lw v0, 0(a0) # copy words addu a0, a0, 4 addu a1, a1, 4 bne a0, a3, 2b sw v0, -4(a1)smallcpy: ble a2, zero, 2f addu a3, a2, a0 # compute ending address1: lbu v0, 0(a0) # copy bytes addu a0, a0, 1 addu a1, a1, 1 bne a0, a3, 1b sb v0, -1(a1)2: sw zero, UADDR+U_PCB_ONFAULT # for copyin, copyout j ra move v0, zero .set reorderEND(bcopy)/* * 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: lb t0, 0(a0) sb t0, 0(a1) sub a2, a2, 1 beq t0, zero, 2f add a0, a0, 1 add a1, a1, 1 bne a2, zero, 1b2: beq a3, zero, 3f sub a2, t2, a2 # compute length copied sw a2, 0(a3)3: sw zero, UADDR+U_PCB_ONFAULT # for copyinstr, copyoutstr move v0, zero j raEND(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; */LEAF(copyinstr) li v0, COPYERR blt a0, zero, copyerr # make sure address is in user space sw v0, UADDR+U_PCB_ONFAULT b copystrEND(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; */LEAF(copyoutstr) li v0, COPYERR blt a1, zero, copyerr # make sure address is in user space sw v0, UADDR+U_PCB_ONFAULT b copystrEND(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; */LEAF(copyin) li v0, COPYERR blt a0, zero, copyerr # make sure address is in user space sw v0, UADDR+U_PCB_ONFAULT b bcopyEND(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; */LEAF(copyout) li v0, COPYERR blt a1, zero, copyerr # make sure address is in user space sw v0, UADDR+U_PCB_ONFAULT b bcopyEND(copyout)LEAF(copyerr) li v0, EFAULT # return error j raEND(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; */#ifdef NOTDEFLEAF(CopyToBuffer) blez a2, 2f1: lhu t0, 0(a0) # read 2 bytes of data subu a2, a2, 2 addu a0, a0, 2 addu a1, a1, 4 sh t0, -4(a1) # write 2 bytes of data to buffer bgtz a2, 1b2: j raEND(CopyToBuffer)#endif /* NOTDEF *//* * 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 blt a2, 2, 7f # at least 2 bytes to copy?1: 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 sb t0, -1(a1) bge a2, 2, 1b3: blt a2, 2, 7f # at least 2 bytes to copy?6: 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 sh t0, -2(a1) bge a2, 2, 6b7: ble a2, zero, 9f # done? lhu t0, 0(a0) # copy one more byte sb t0, 0(a1)9: j raEND(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) addu v0, v0, 4 bne v1, t1, 1b /* 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) .set noreorder 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, zero .set reorderEND(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 ## PANIC("setrunqueue") ##1: lbu t0, P_PRIORITY(a0) # put on p->p_priority / 4 queue srl t0, t0, 2 # compute index into 'whichqs' li t1, 1 # compute corresponding bit sll t1, t1, t0 lw t2, whichqs # set corresponding bit 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 addu sp, sp, STAND_FRAME_SIZE j raEND(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 srl t0, t0, 2 # compute index into 'whichqs' li t1, 1 # compute corresponding bit sll t1, t1, t0 lw t2, whichqs # check corresponding bit and v0, t2, t1 sw ra, STAND_RA_OFFSET(sp) ## bne v0, zero, 1f ## PANIC("remrq") ## it wasn't recorded to be on its q1: lw v0, P_BACK(a0) # v0 = p->p_back lw v1, P_FORW(a0) # v1 = p->p_forw 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 bne v0, t0, 2f # No. qp->ph_link != qp xor t2, t2, t1 # clear corresponding bit in 'whichqs' sw t2, whichqs2: sw zero, P_BACK(a0) ## for firewall checking addu sp, sp, STAND_FRAME_SIZE j raEND(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) .set noreorder 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. .set reorder li sp, KERNELSTACK - START_FRAME # switch to standard stack b cpu_switchEND(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) .set noreorder 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 interrupts .set reorderEND(idle)/* * cpu_switch() * Find the highest priority process and resume it. */NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra) .set noreorder 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: add 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 # save p move a0, s0 # restore p sw a0, curproc # set curproc sll v0, v0, VMMACH_TLB_PID_SHIFT # v0 = aligned PID lw t0, P_UPTE+0(a0) # t0 = first u. pte lw t1, P_UPTE+4(a0) # 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -