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

📄 locore.s

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