⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 locore.s

📁 早期freebsd实现
💻 S
📖 第 1 页 / 共 5 页
字号:
	.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 + -