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

📄 locore.s

📁 早期freebsd实现
💻 S
📖 第 1 页 / 共 5 页
字号:
	STRAP(0xb3)	STRAP(0xb4)	STRAP(0xb5)	STRAP(0xb6)	STRAP(0xb7)	STRAP(0xb8)	STRAP(0xb9)	STRAP(0xba)	STRAP(0xbb)	STRAP(0xbc)	STRAP(0xbd)	STRAP(0xbe)	STRAP(0xbf)	STRAP(0xc0)	STRAP(0xc1)	STRAP(0xc2)	STRAP(0xc3)	STRAP(0xc4)	STRAP(0xc5)	STRAP(0xc6)	STRAP(0xc7)	STRAP(0xc8)	STRAP(0xc9)	STRAP(0xca)	STRAP(0xcb)	STRAP(0xcc)	STRAP(0xcd)	STRAP(0xce)	STRAP(0xcf)	STRAP(0xd0)	STRAP(0xd1)	STRAP(0xd2)	STRAP(0xd3)	STRAP(0xd4)	STRAP(0xd5)	STRAP(0xd6)	STRAP(0xd7)	STRAP(0xd8)	STRAP(0xd9)	STRAP(0xda)	STRAP(0xdb)	STRAP(0xdc)	STRAP(0xdd)	STRAP(0xde)	STRAP(0xdf)	STRAP(0xe0)	STRAP(0xe1)	STRAP(0xe2)	STRAP(0xe3)	STRAP(0xe4)	STRAP(0xe5)	STRAP(0xe6)	STRAP(0xe7)	STRAP(0xe8)	STRAP(0xe9)	STRAP(0xea)	STRAP(0xeb)	STRAP(0xec)	STRAP(0xed)	STRAP(0xee)	STRAP(0xef)	STRAP(0xf0)	STRAP(0xf1)	STRAP(0xf2)	STRAP(0xf3)	STRAP(0xf4)	STRAP(0xf5)	STRAP(0xf6)	STRAP(0xf7)	STRAP(0xf8)	STRAP(0xf9)	STRAP(0xfa)	STRAP(0xfb)	STRAP(0xfc)	STRAP(0xfd)	STRAP(0xfe)	STRAP(0xff)	/* the message buffer is always mapped */_msgbufmapped:	.word	1#ifdef DEBUG/* * A hardware red zone is impossible.  We simulate one in software by * keeping a `red zone' pointer; if %sp becomes less than this, we panic. * This is expensive and is only enabled when debugging. */#define	REDSIZE	(8*96)		/* some room for bouncing */#define	REDSTACK 2048		/* size of `panic: stack overflow' region */	.data_redzone:	.word	_idle_u + REDSIZE_redstack:	.skip	REDSTACK	.textLpanic_red:	.asciz	"stack overflow"	ALIGN	/* set stack pointer redzone to base+minstack; alters base */#define	SET_SP_REDZONE(base, tmp) \	add	base, REDSIZE, base; \	sethi	%hi(_redzone), tmp; \	st	base, [tmp + %lo(_redzone)]	/* variant with a constant */#define	SET_SP_REDZONE_CONST(const, tmp1, tmp2) \	set	(const) + REDSIZE, tmp1; \	sethi	%hi(_redzone), tmp2; \	st	tmp1, [tmp2 + %lo(_redzone)]	/* check stack pointer against redzone (uses two temps) */#define	CHECK_SP_REDZONE(t1, t2) \	sethi	%hi(_redzone), t1; \	ld	[t1 + %lo(_redzone)], t2; \	cmp	%sp, t2;	/* if sp >= t2, not in red zone */ \	bgeu	7f; nop;	/* and can continue normally */ \	/* move to panic stack */ \	st	%g0, [t1 + %lo(_redzone)]; \	set	_redstack + REDSTACK - 96, %sp; \	/* prevent panic() from lowering ipl */ \	sethi	%hi(_panicstr), t2; \	set	Lpanic_red, t2; \	st	t2, [t1 + %lo(_panicstr)]; \	rd	%psr, t1;		/* t1 = splhigh() */ \	or	t1, PSR_PIL, t2; \	wr	t2, 0, %psr; \	wr	t2, PSR_ET, %psr;	/* turn on traps */ \	nop; nop; nop; \	save	%sp, -96, %sp;		/* preserve current window */ \	sethi	%hi(Lpanic_red), %o0; \	call	_panic; or %o0, %lo(Lpanic_red), %o0; \7:#else#define	SET_SP_REDZONE(base, tmp)#define	SET_SP_REDZONE_CONST(const, t1, t2)#define	CHECK_SP_REDZONE(t1, t2)#endif/* * The window code must verify user stack addresses before using them. * A user stack pointer is invalid if: *	- it is not on an 8 byte boundary; *	- its pages (a register window, being 64 bytes, can occupy *	  two pages) are not readable or writable. * We define three separate macros here for testing user stack addresses. * * PTE_OF_ADDR locates a PTE, branching to a `bad address' *	handler if the stack pointer points into the hole in the *	address space (i.e., top 3 bits are not either all 1 or all 0); * CMP_PTE_USER_READ compares the located PTE against `user read' mode; * CMP_PTE_USER_WRITE compares the located PTE against `user write' mode. * The compares give `equal' if read or write is OK. * * Note that the user stack pointer usually points into high addresses * (top 3 bits all 1), so that is what we check first. * * The code below also assumes that PTE_OF_ADDR is safe in a delay * slot; it is, at it merely sets its `pte' register to a temporary value. */	/* input: addr, output: pte; aux: bad address label */#define	PTE_OF_ADDR(addr, pte, bad) \	sra	addr, PG_VSHIFT, pte; \	cmp	pte, -1; \	be,a	1f; andn addr, 4095, pte; \	tst	pte; \	bne	bad; EMPTY; \	andn	addr, 4095, pte; \1:	/* input: pte; output: condition codes */#define	CMP_PTE_USER_READ(pte) \	lda	[pte] ASI_PTE, pte; \	srl	pte, PG_PROTSHIFT, pte; \	andn	pte, (PG_W >> PG_PROTSHIFT), pte; \	cmp	pte, PG_PROTUREAD	/* input: pte; output: condition codes */#define	CMP_PTE_USER_WRITE(pte) \	lda	[pte] ASI_PTE, pte; \	srl	pte, PG_PROTSHIFT, pte; \	cmp	pte, PG_PROTUWRITE/* * The calculations in PTE_OF_ADDR and CMP_PTE_USER_* are rather slow: * in particular, according to Gordon Irlam of the University of Adelaide * in Australia, these consume at least 18 cycles on an SS1 and 37 on an * SS2.  Hence, we try to avoid them in the common case. * * A chunk of 64 bytes is on a single page if and only if: * *	((base + 64 - 1) & ~4095) == (base & ~4095) * * Equivalently (and faster to test), the low order bits (base & 4095) must * be small enough so that the sum (base + 63) does not carry out into the * upper page-address bits, i.e., * *	(base & 4095) < (4096 - 63) * * so we allow testing that here.  This macro is also assumed to be safe * in a delay slot (modulo overwriting its temporary). */#define	SLT_IF_1PAGE_RW(addr, tmp) \	and	addr, 4095, tmp; \	cmp	tmp, (4096 - 63)/* * Every trap that enables traps must set up stack space. * If the trap is from user mode, this involves switching to the kernel * stack for the current process, and we must also set cpcb->pcb_uw * so that the window overflow handler can tell user windows from kernel * windows. * * The number of user windows is: * *	cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows * * (where pcb_wim = log2(current %wim) and CWP = low 5 bits of %psr). * We compute this expression by table lookup in uwtab[CWP - pcb_wim], * which has been set up as: * *	for i in [-nwin+1 .. nwin-1] *		uwtab[i] = (nwin - 1 - i) % nwin; * * (If you do not believe this works, try it for yourself.) * * We also keep one or two more tables: * *	for i in 0..nwin-1 *		wmask[i] = 1 << ((i + 1) % nwindows); * * wmask[CWP] tells whether a `rett' would return into the invalid window. */	.data	.skip	32			! alignment byte & negative indiciesuwtab:	.skip	32			! u_char uwtab[-31..31];wmask:	.skip	32			! u_char wmask[0..31];	.text/* * Things begin to grow uglier.... * * Each trap handler may (always) be running in the trap window. * If this is the case, it cannot enable further traps until it writes * the register windows into the stack (or, if the stack is no good, * the current pcb). * * ASSUMPTIONS: TRAP_SETUP() is called with: *	%l0 = %psr *	%l1 = return pc *	%l2 = return npc *	%l3 = (some value that must not be altered) * which means we have 4 registers to work with. * * The `stackspace' argument is the number of stack bytes to allocate * for register-saving, and must be at least -64 (and typically more, * for global registers and %y). * * Trapframes should use -CCFSZ-80.  (80 = sizeof(struct trapframe); * see trap.h.  This basically means EVERYONE.  Interrupt frames could * get away with less, but currently do not.) * * The basic outline here is: * *	if (trap came from kernel mode) { *		if (we are in the trap window) *			save it away; *		%sp = %fp - stackspace; *	} else { *		compute the number of user windows; *		if (we are in the trap window) *			save it away; *		%sp = (top of kernel stack) - stackspace; *	} * * Again, the number of user windows is: * *	cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows * * (where pcb_wim = log2(current %wim) and CWP is the low 5 bits of %psr), * and this is computed as `uwtab[CWP - pcb_wim]'. * * NOTE: if you change this code, you will have to look carefully * at the window overflow and underflow handlers and make sure they * have similar changes made as needed. */#define	CALL_CLEAN_TRAP_WINDOW \	sethi	%hi(clean_trap_window), %l7; \	jmpl	%l7 + %lo(clean_trap_window), %l4; \	 mov	%g7, %l7	/* save %g7 in %l7 for clean_trap_window */#define	TRAP_SETUP(stackspace) \	rd	%wim, %l4; \	mov	1, %l5; \	sll	%l5, %l0, %l5; \	btst	PSR_PS, %l0; \	bz	1f; \	 btst	%l5, %l4; \	/* came from kernel mode; cond codes indicate trap window */ \	bz,a	3f; \	 add	%fp, stackspace, %sp;	/* want to just set %sp */ \	CALL_CLEAN_TRAP_WINDOW;		/* but maybe need to clean first */ \	b	3f; \	 add	%fp, stackspace, %sp; \1: \	/* came from user mode: compute pcb_nw */ \	sethi	%hi(_cpcb), %l6; \	ld	[%l6 + %lo(_cpcb)], %l6; \	ld	[%l6 + PCB_WIM], %l5; \	and	%l0, 31, %l4; \	sub	%l4, %l5, %l5; \	set	uwtab, %l4; \	ldub	[%l4 + %l5], %l5; \	st	%l5, [%l6 + PCB_UW]; \	/* cond codes still indicate whether in trap window */ \	bz,a	2f; \	 sethi	%hi(UPAGES*NBPG+(stackspace)), %l5; \	/* yes, in trap window; must clean it */ \	CALL_CLEAN_TRAP_WINDOW; \	sethi	%hi(_cpcb), %l6; \	ld	[%l6 + %lo(_cpcb)], %l6; \	sethi	%hi(UPAGES*NBPG+(stackspace)), %l5; \2: \	/* trap window is (now) clean: set %sp */ \	or	%l5, %lo(UPAGES*NBPG+(stackspace)), %l5; \	add	%l6, %l5, %sp; \	SET_SP_REDZONE(%l6, %l5); \3: \	CHECK_SP_REDZONE(%l6, %l5)/* * Interrupt setup is almost exactly like trap setup, but we need to * go to the interrupt stack if (a) we came from user mode or (b) we * came from kernel mode on the kernel stack. */#define	INTR_SETUP(stackspace) \	rd	%wim, %l4; \	mov	1, %l5; \	sll	%l5, %l0, %l5; \	btst	PSR_PS, %l0; \	bz	1f; \	 btst	%l5, %l4; \	/* came from kernel mode; cond codes still indicate trap window */ \	bz,a	0f; \	 sethi	%hi(_eintstack), %l7; \	CALL_CLEAN_TRAP_WINDOW; \	sethi	%hi(_eintstack), %l7; \0:	/* now if %fp >= eintstack, we were on the kernel stack */ \	cmp	%fp, %l7; \	bge,a	3f; \	 add	%l7, stackspace, %sp;	/* so switch to intstack */ \	b	4f; \	 add	%fp, stackspace, %sp;	/* else stay on intstack */ \1: \	/* came from user mode: compute pcb_nw */ \	sethi	%hi(_cpcb), %l6; \	ld	[%l6 + %lo(_cpcb)], %l6; \	ld	[%l6 + PCB_WIM], %l5; \	and	%l0, 31, %l4; \	sub	%l4, %l5, %l5; \	set	uwtab, %l4; \	ldub	[%l4 + %l5], %l5; \	st	%l5, [%l6 + PCB_UW]; \	/* cond codes still indicate whether in trap window */ \	bz,a	2f; \	 sethi	%hi(_eintstack), %l7; \	/* yes, in trap window; must save regs */ \	CALL_CLEAN_TRAP_WINDOW; \	sethi	%hi(_eintstack), %l7; \2: \	add	%l7, stackspace, %sp; \3: \	SET_SP_REDZONE_CONST(_intstack, %l6, %l5); \4: \	CHECK_SP_REDZONE(%l6, %l5)/* * Handler for making the trap window shiny clean. * * On entry: *	cpcb->pcb_nw = number of user windows *	%l0 = %psr *	%l1 must not be clobbered *	%l2 must not be clobbered *	%l3 must not be clobbered *	%l4 = address for `return' *	%l7 = saved %g7 (we put this in a delay slot above, to save work) * * On return: *	%wim has changed, along with cpcb->pcb_wim *	%g7 has been restored * * Normally, we push only one window. */clean_trap_window:	mov	%g5, %l5		! save %g5	mov	%g6, %l6		! ... and %g6/*	mov	%g7, %l7		! ... and %g7 (already done for us) */	sethi	%hi(_cpcb), %g6		! get current pcb	ld	[%g6 + %lo(_cpcb)], %g6	/* Figure out whether it is a user window (cpcb->pcb_uw > 0). */	ld	[%g6 + PCB_UW], %g7	deccc	%g7	bge	ctw_user	 save	%g0, %g0, %g0		! in any case, enter window to save	/* The window to be pushed is a kernel window. */	std	%l0, [%sp + (0*8)]ctw_merge:	std	%l2, [%sp + (1*8)]	std	%l4, [%sp + (2*8)]	std	%l6, [%sp + (3*8)]	std	%i0, [%sp + (4*8)]	std	%i2, [%sp + (5*8)]	std	%i4, [%sp + (6*8)]	std	%i6, [%sp + (7*8)]	/* Set up new window invalid mask, and update cpcb->pcb_wim. */	rd	%psr, %g7		! g7 = (junk << 5) + new_cwp	mov	1, %g5			! g5 = 1 << new_cwp;	sll	%g5, %g7, %g5	wr	%g5, 0, %wim		! setwim(g5);	and	%g7, 31, %g7		! cpcb->pcb_wim = g7 & 31;	st	%g7, [%g6 + PCB_WIM]	nop	restore				! back to trap window	mov	%l5, %g5		! restore g5	mov	%l6, %g6		! ... and g6	jmp	%l4 + 8			! return to caller	 mov	%l7, %g7		! ... and g7	/* NOTREACHED */ctw_user:	/*	 * The window to be pushed is a user window.	 * We must verify the stack pointer (alignment & permissions).	 * See comments above definition of PTE_OF_ADDR.	 */	st	%g7, [%g6 + PCB_UW]	! cpcb->pcb_uw--;	btst	7, %sp			! if not aligned,	bne	ctw_invalid		! choke on it	 EMPTY	PTE_OF_ADDR(%sp, %g7, ctw_invalid)	CMP_PTE_USER_WRITE(%g7)		! likewise if not writable	bne	ctw_invalid	 EMPTY	SLT_IF_1PAGE_RW(%sp, %g7)	bl,a	ctw_merge		! all ok if only 1	 std	%l0, [%sp]	add	%sp, 7*8, %g5		! check last addr too	PTE_OF_ADDR(%g5, %g7, ctw_invalid)	CMP_PTE_USER_WRITE(%g7)	be,a	ctw_merge		! all ok: store <l0,l1> and merge	 std	%l0, [%sp]

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -