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

📄 code.c

📁 pebble
💻 C
📖 第 1 页 / 共 2 页
字号:
		*p++ = SD(T2, S_T2*8, base);
		*p++ = SD(T3, S_T3*8, base);
		*p++ = SD(T4, S_T4*8, base);
		*p++ = SD(T5, S_T5*8, base);
		*p++ = SD(T6, S_T6*8, base);
		*p++ = SD(T7, S_T7*8, base);
		*p++ = SD(T8, S_T8*8, base);
		*p++ = SD(T9, S_T9*8, base);
		*p++ = SD(V0, S_LO*8, base);
		*p++ = SD(V1, S_HI*8, base);
	}

	if (PORTAL_LOG)
		p = gen_write_log_portal(p, A0);

	p = gen_li(p, T0,
		(int)lookup_portal_rtn(stack_type, stack_save,
			window_reg, window_type));
	*p++ = SD(T0, S_PORTAL_RTN*8, base);
	while ((p - last_mtc) <= MTC0_TO_TLB_OP)
		*p++ = NOP;

	*p++ = TLBR;
	*p++ = LW(T1, THR_STACK_DESC*4, treg);
	*p++ = LW(T8, THR_STACK_Q*4, treg);
	*p++ = LW(T6, THR_PORTAL_TBL*4, treg);
	*p++ = LD(T7, THR_PTE*4, treg);
	*p++ = DMFC0(T4, C0_EPC);
	*p++ = MFC0(T5, C0_STATUS);
	*p++ = DMFC0(T2, C0_TLBHI);
	*p++ = DMFC0(T3, C0_TLBLO0);
	if (stack_type != STACK_EXCEPTION)
		*p++ = DADDIU(T4, T4, 4);
	*p++ = SD(T4, S_EPC*8, base);
	*p++ = SW(T5, S_STATUS*8, base);
	if (asid_reg != 0)
		*p++ = ANDI(asid_reg, T2, TLBHI_PIDMASK);
	*p++ = SD(T2, S_TLBHI*8, base);
	*p++ = SD(T3, S_TLBLO0*8, base);
	*p++ = SW(T1, S_STACK_DESC*8, base);
	*p++ = SW(T8, S_STACK_Q*8, base);
	*p++ = SW(T6, S_PORTAL_TBL*8, base);
	*p++ = SD(T7, S_PTE*8, base);

	/* a memory window; could be either 'w', '>' or '=' type */
	if (window_reg != 0) {
		/* check against heap address bounds */
		/* leave the high order byte only */
		*p++ = SRL(T3, window_reg, 24);
		*p++ = SLTIU(T4, T3, (HEAP_START >> 24) & 0xff);
		*p++ = BEQ(T4, ZERO, 3);
		/* always executed in the delay slot */
		*p++ = SLTIU(T5, T3, (HEAP_END >> 24) & 0xff);
		label = p;
		p = gen_j(p, bad_win_call);
		*p++ = NOP;
		/* continue checking of heap address */
		*p++ = BEQ(T5, ZERO, label- (p+1));
		/* compute level 1 page table index in the branch delay slot */
		*p++ = SRL(T3, window_reg, (PAGESHIFT + PTABLE1_SHIFT));
		*p++ = SLL(T3, T3, 3);		/* zero three low-order bits */
		p = gen_lw(p, T4,
		     ((ulong)ptable_level1)+(PTABLE1_L2_ENTRIES*WORD_SIZE), T3);
		p = gen_lw(p, T5,
		     ((ulong)ptable_level1)+(PTABLE1_L2_TABLE*WORD_SIZE), T3);
		/* access level1 page table entry */
		*p++ = SRL(T3, window_reg, (PAGESHIFT-PTESHIFT));
		/* mask only level2 index bits */
		*p++ = ANDI(T3, T3, PAGEMASK - (PTESIZE-1));
		*p++ = SLTU(T4, T3, T4);
		*p++ = BEQ(T4, ZERO, label - (p + 1));
		/* access level2 page table */
		*p++ = ADD(T3, T3, T5);
		*p++ = LW(T4, PTE_ACCESS*4, T3);
		*p++ = ANDI(T2, T2, TLBHI_PIDMASK);
		p = gen_li(p, T7, TLBHI_VPN2MASK);
		*p++ = BEQ(T4, ZERO, label - (p + 1));
		*p++ = AND(T7, T7, window_reg);

		switch (window_type) {
		case 'w':
		case '=':
			/* a regular window or a shared window */
			*p++ = ORI(T7, T7, new_asid & TLBHI_PIDMASK);
			*p++ = SD(T7, S_WIN_VADDR*8, base);
			/* check if caller had access rights to page */
			*p++ = ADD(T5, T4, T2);
			*p++ = LB(T6, 0, T5);
			*p++ = ADDI(T7, T4, new_asid & TLBHI_PIDMASK);
			*p++ = BEQ(T6, ZERO, label - (p + 1));
			/* increase the callee's access count */
			*p++ = LB(T8, 0, T7);
			*p++ = ADDIU(T8, T8, 1);
			/* did the callee access count overflow? */
			*p++ = ANDI(T8, T8, 0xff);
			*p++ = BEQ(T8, ZERO, label - (p + 1));
			*p++ = SD(T7, S_WIN_COUNT*8, base);
			*p++ = SB(T8, 0, T7);
			break;

		case '>':
			/* give window to called domain */
			/* check if caller had access rights to page */
			*p++ = ADD(T5, T4, T2);
			*p++ = LB(T6, 0, T5);
			*p++ = LB(T8, new_asid & TLBHI_PIDMASK, T4);
			*p++ = BEQ(T6, ZERO, label - (p + 1));
			/* branch delay slot here */
			*p++ = ADDIU(T8, T8, 1);
			*p++ = ANDI(T8, T8, 0xff);
			/* did the callee access count overflow? */
			*p++ = BEQ(T8, ZERO, label - (p + 1));
			/* branch delay slot here */
			*p++ = ADDIU(T6, T6, -1);

			/* set the caller and callee counters */
			*p++ = SB(T6, 0, T5);
			*p++ = SB(T8, new_asid & TLBHI_PIDMASK, T4);

			start = p;
			label9 = label10 = p;
			/* must generate code twice to get correct branch */
			/* offsets */
			for (i = 0; i < 2; i++) {
				p = start;

				/* change page ownership if calling domain */
				/* can not access the page any longer */
				*p++ = BNE(T6, ZERO, label10 - (p + 1));
				/* branch delay slot */
				/* T7 contains the window's starting address */
				*p++ = ORI(T8, T7, new_asid & TLBHI_PIDMASK);
				*p++ = LB(T6, NASID, T5);

				/* change page owner domain to "new_asid" */
				*p++ = SW(T8, PTE_HI*4, T3);

				/* was this page loaded to the TLB? */
				*p++ = BNE(T6, ZERO, label10 - (p + 1));
				/* reset caller's TLB load flag */
				*p++ = SB(T1, NASID, T5);

				/* yes, it was loaded to the TLB */
				/* remove TLB entry from caller */
				/* T2 contains the caller's ASID */
				*p++ = OR(T7, T7, T2);
				p = gen_tlb_probe_erase(p, T7, label9);
				label9 = p;
				/* ASID will be loaded by gen_restrpc */
				/* fix C0_INDEX that was changed by tlb_probe */
				*p++ = MTC0(ZERO, C0_INDEX);
				label10 = p;
			}
			break;

		default:
			panic(
			"portal manager: gen_savereg: invalid window type");
		}
	}

	if (stack_save != SAVE_MINIMAL) {
		*p++ = SD(S0, S_S0*8, base);
		*p++ = SD(S1, S_S1*8, base);
		*p++ = SD(S2, S_S2*8, base);
		*p++ = SD(S3, S_S3*8, base);
		*p++ = SD(S4, S_S4*8, base);
		*p++ = SD(S5, S_S5*8, base);
		*p++ = SD(S6, S_S6*8, base);
		*p++ = SD(S7, S_S7*8, base);
		*p++ = SD(S8, S_S8*8, base);
	}
	*p++ = SD(GP, S_GP*8, base);
	*p++ = SD(SP, S_SP*8, base);
	*p++ = SD(RA, S_RA*8, base);


	return p;
}


/*
 * Note: gen_savereg must not change T9!
 * gen_pushreg can also leave the most recent bad virtual address in
 * the register specified by bad_vaddr_reg.
 */
static int *
gen_pushreg(int *p, int treg, PortalStack stack_type, PortalSave stack_save,
	uint asid_reg, uint window_reg, uchar window_type,
	uint bad_vaddr_reg, uint new_asid, int *last_mtc)
{
	*p++ = LW(K1, THR_CALL_SP*4, treg);
	if (stack_type != STACK_EXCEPTION)
		*p++ = LW(T9, THR_CALL_LO*4, treg);
	*p++ = DADDIU(K1, K1, -8*S_REGS);
	*p++ = SW(K1, THR_CALL_SP*4, treg);
	p = gen_savereg(p, treg, K1, stack_type, stack_save, asid_reg,
		window_reg, window_type, new_asid, last_mtc);
	if (bad_vaddr_reg != 0)
		*p++ = MFC0(bad_vaddr_reg, C0_BADVADDR);
	if (stack_type != STACK_EXCEPTION) {
		*p++ = SLTU(T2, K1, T9);
		*p++ = BEQ(T2, ZERO, 3);
		*p++ = NOP;
		p = gen_j(p, thr_stack_overflow);
		*p++ = MOVE(A0, treg);
	}

	return p;
}


/*
 *	assumption: C0_INDEX is zero on entry.
 *
 *	If the stack type is exception, we set register A2 to
 * 	!= 0 if we indeed switched to exception stack,
 *	Otherwise, it is zero, which indicates a nested exception
 *	while serving a previous exception.
 */
static int *
gen_restrpc(int *p, int treg, int asid, int status, int gp, int portal_tbl,
	int (*entry)(),
	int *epilog, vlong domain_ptable, PortalStack stack_type,
	StackQ *stack_q, int *last_mtc)
{
	int *old_p;
	int *last_tlbr = NULL;
	Ptable1Union ptable_convert;

	DIAG(PORTAL_DIAG, ("gen_restrpc asid=%d status=%08x gp=%08x portal_tbl=%08x entry=%08x epilog=%08x\n",
		asid, status, gp, portal_tbl, (uint)entry, (uint)epilog));
	DIAG(PORTAL_DIAG, ("stack_type=%d stack_q=%p\n", stack_type, stack_q));

	ptable_convert.x = domain_ptable;
	DIAG(PORTAL_DIAG, ("private_ptable.pte=%p entries=%d\n",
		(PTE *)ptable_convert.s.v[PTABLE1_L2_TABLE],
		(int)ptable_convert.s.v[PTABLE1_L2_ENTRIES]));

	if (stack_type == STACK_SHARED) {
		while ((p - last_mtc) <= MTC0_TO_TLB_OP)
			*p++ = NOP;
		last_tlbr = p;
		*p++ = TLBR;
	}

	switch (stack_type) {
	case STACK_EXCEPTION:
		p = gen_li(p, T2, (excpt_stack_tlbhi & ~TLBHI_PIDMASK) | asid);
		p = gen_li(p, T7, excpt_stack_tlblo0);
		*p++ = SW(ZERO, THR_STACK_Q*4, treg);

		/* switch stack descriptors */
		/* interrupt stack descriptor is zero (until we know better) */
		*p++ = SW(ZERO, THR_STACK_DESC*4, treg);

		/* switch stacks only if not using exception stack already */
		p = gen_li(p, T3, excpt_stack_sp);
		*p++ = XOR(A2, T3, SP);
		*p++ = SRL(A2, A2, PAGESHIFT);
		/* A2 is != 0 if we switched to exception stack */
		/* A2 is zero if this is a nested exception, */
		/* which means that we are using the same stack */
		/* note: we pass this condition in the 3rd parameter to the */
		/* interrupt handler */
		*p++ = MOVN(SP, T3, A2);
		*p++ = DMFC0(A3, C0_BADVADDR);
		break;

	case STACK_QUEUE:
		p = gen_li(p, T1, (int)stack_q);
		*p++ = LW(T4, STACK_Q_HEAD*4, T1);
		*p++ = SW(T1, THR_STACK_Q*4, treg);
		*p++ = TEQI(T4, 0);	/* trap if queue is empty */
		*p++ = LW(T3, STACK_DESC_NEXT*4, T4);
		*p++ = LW(T2, STACK_DESC_TLBHI*4, T4);
		*p++ = LW(T7, STACK_DESC_TLBLO0*4, T4);
		*p++ = SW(T3, STACK_Q_HEAD*4, T1);
		*p++ = LW(SP, STACK_DESC_SP*4, T4);
		*p++ = SW(T4, THR_STACK_DESC*4, treg);
		p = gen_li(p, T6, ~TLBHI_PIDMASK);
		break;

	case STACK_SHARED:
		*p++ = SW(ZERO, THR_STACK_Q*4, treg);
		p = gen_li(p, T6, ~TLBHI_PIDMASK);
		/* must wait some cycles between TLBR and DMFC0 (on RM7000) */
		while ((p - last_tlbr) <= TLBR_TO_MFC0)
			*p++ = NOP;
		*p++ = DMFC0(T2, C0_TLBHI);
		break;

	default:
		panic("gen_restrpc: invalid stack_type value");
	}

	/* generate new ASID and keep the same stack mapping */
	if (stack_type == STACK_QUEUE || stack_type == STACK_SHARED) {
		*p++ = AND(T2, T2, T6);
		*p++ = ORI(T2, T2, asid);
	}
	*p++ = DMTC0(T2, C0_TLBHI);
	p = gen_li(p, T3, status);
	*p++ = MTC0(T3, C0_STATUS);
	p = gen_li(p, T4, (int)entry);
	*p++ = DMTC0(T4, C0_EPC);
	if (stack_type == STACK_EXCEPTION || stack_type == STACK_QUEUE) {
		*p++ = DMTC0(T7, C0_TLBLO0);
		*p++ = DADDIU(T7, T7, TLBLO0toLO1);
		*p++ = DMTC0(T7, C0_TLBLO1);
		*p++ = MTC0(ZERO, C0_PAGEMASK);
	}

	p = gen_li(p, T5, portal_tbl);
	p = gen_li(p, T7, (int)ptable_convert.s.v[PTABLE1_L2_TABLE]);
	p = gen_li(p, T8, (int)ptable_convert.s.v[PTABLE1_L2_ENTRIES]);
	*p++ = SW(T5, THR_PORTAL_TBL*4, treg);
	*p++ = SW(T7, THR_PTE*4, treg);
	*p++ = SW(T8, THR_L2_ENTRIES*4, treg);
	*p++ = TLBWI;

	old_p = p;
	p = gen_li(p, GP, gp);
	/* Note: we do not clear FP (S8) here */
	/* If we do, we must save/restore it also in SAVE_MINIMAL */
	/* p = gen_li(p, S8, 0); */
	p = gen_li(p, RA, (int)epilog);

	/* TLBWI must be followed by at least TLBW_TO_BRANCH integer  */
	/* instructions */
	while ((p - old_p) < TLBW_TO_BRANCH)
		*p++ = NOP;

	return p;
}


/*
 * The null portal transfers control to the destination domain without
 * saving the context of the calling domain.
 *
 * The null portal should be traversed only in two cases:
 * a.	When the initialization domain relinquishes control to the scheduler.
 *	The scheduler NEVER returns to the initialization domain!
 * b.	When the interrupt dispatcher finishes its work.
 *	In this case we want the scheduler to pick the next thread to run.
 *	If the scheduler picks the calling thread, then we should return
 *	to the domain that was interrupted, and not to the interrupt handler
 *	domain.
 *
 * Return the virtual address of the portal code.
 */
Portal
gen_null_portal(vlong *save_p, int (*entry)(), int *portal_len)
{
	int *p, *start, *phys_start;
	int len;

	DIAG(PORTAL_DIAG, ("gen_null_portal: save_p=%08x entry=%08x\n", (uint)save_p, (uint)entry));

	if (portal_code == NULL)
		portal_code = (int *)malloc(MAX_PORTAL_LEN);
	p = portal_code;

	if (PORTAL_LOG)
		p = gen_write_log_portal(p, A0);

	*p++ = MTC0(ZERO, C0_INDEX);
	p = gen_restrpc(p, K0, (int)save_p[S_TLBHI] & TLBHI_PIDMASK,
		(int)save_p[S_STATUS],
		(int)save_p[S_GP], (int)save_p[S_PORTAL_TBL], entry, 0,
		save_p[S_PTE], STACK_SHARED, NULL, p-1);
	*p++ = MOVE(A0, A1);
	*p++ = MOVE(A1, A2);
	*p++ = MOVE(A2, A3);

	if (PORTAL_LOG) {
		*p++ = LW(K1, THR_CALL_SP*4, K0);
		p = gen_li(p, T5, (int)save_p[S_TLBHI] & TLBHI_PIDMASK);
		p = gen_write_log(p, K0, K1, T5, A0, A1);
	}
	*p++ = ERET;

	/* pad resulting code to 8 byte boundary */
	while ((uint)p & 07)
		*p++ = NOP;

	len = p - portal_code;
	if (len*sizeof(int) > MAX_PORTAL_LEN)
		panic("portal code overflow");

	start = (int *)aligned_malloc(len*sizeof(int));
	memcpy((char *)start, (char *)portal_code, len*sizeof(int));

	phys_start = (int *)PA_TO_KVA0((ulong)virt2phys(start));
	clean_cache(phys_start, len*sizeof(int));
	clean_cache(start, len*sizeof(int));
	*portal_len = len;

	return (Portal)start;
}

/*
 * Generate a portal and return the virtual address of the portal code.
 */
Portal
gen_portal(vlong *save_p, int (*entry)(), int *epilog,
	PortalStack stack_type, PortalSave stack_save, StackQ *stack_q,
	uint thread_reg, uint const_reg, int c, uint asid_reg, uint window_reg,
	uchar window_type, uint bad_vaddr_reg,
	int *portal_len, int *const_offset, int *c_reg)
{
	int *p, *start, *phys_start;
	int len;
	int *last_mtc;

	/* the portal code is created in a single large buffer, */
	/* "portal_code", which is allocated by the first call to gen_portal */
	if (portal_code == NULL)
		portal_code = (int *)malloc(MAX_PORTAL_LEN);
	p = portal_code;

	last_mtc = p;

	*p++ = MTC0(ZERO, C0_INDEX);
	p = gen_pushreg(p, K0, stack_type, stack_save, asid_reg, window_reg,
		window_type,
		bad_vaddr_reg, (int)save_p[S_TLBHI] & TLBHI_PIDMASK, last_mtc);
	p = gen_restrpc(p, K0, (int)save_p[S_TLBHI] & TLBHI_PIDMASK,
		(int)save_p[S_STATUS], (int)save_p[S_GP],
		(int)save_p[S_PORTAL_TBL], entry, epilog, save_p[S_PTE],
		stack_type, stack_q, last_mtc);

	/* increase stack pointer for parameters #4 and #5 */
	if (thread_reg > A3 || const_reg > A3) {
		if ((thread_reg == (A3+2) || const_reg == (A3+2)) &&
		     PARAM_SIZE == 8)
			/* new calling sequence: two synthetic parameters */
			/* each parameter is passed in 8 bytes */
			*p++ = ADDIU(SP, SP, -16);
		else
			/* old calling sequence: every parameter is passed */
			/* in 4 bytes and the stack pointer is double-word */
			/* aligned. */
			/* Thus both one and two synthetic parameters */
			/* increase the stack by 8 bytes */
			*p++ = ADDIU(SP, SP, -8);
	}

	if (thread_reg != 0) {
		if (thread_reg <= A3)
			*p++ = MOVE(thread_reg, K0);
		else
			*p++ = SW(K0, SAVEREGS + PARAM_SIZE*(thread_reg-(A3+1)),
				SP);
	}

	if (const_reg != 0) {
		*const_offset = p - portal_code;
		if (const_reg <= A3) {
			p = gen_li_2inst(p, const_reg, c);
			*c_reg = const_reg;
		} else	{
			p = gen_li_2inst(p, T0, c);
			*p++ = SW(T0, SAVEREGS + PARAM_SIZE*(const_reg-(A3+1)),
				SP);
			*c_reg = T0;
		}
	} else {
		*const_offset = 0;
		*c_reg = ZERO;
	}

	if (PORTAL_LOG) {
		p = gen_li(p, T5, (int)save_p[S_TLBHI] & TLBHI_PIDMASK);
		*p++ = LW(K1, THR_CALL_SP*4, K0);
		p = gen_write_log(p, K0, K1, T5, A0, A1);
	}

	*p++ = ERET;

	/* pad resulting code to 8 byte boundary */
	while ((uint)p & 07)
		*p++ = NOP;

	len = p - portal_code;
	if (len*sizeof(int) > MAX_PORTAL_LEN)
		panic("portal code overflow");

	start = (int *)aligned_malloc(len*sizeof(int));
	memcpy((char *)start, (char *)portal_code, len*sizeof(int));

	phys_start = (int *)PA_TO_KVA0((ulong)virt2phys(start));
	clean_cache(phys_start, len*sizeof(int));
	clean_cache(start, len*sizeof(int));
	*portal_len = len;

	return (Portal)start;
}

⌨️ 快捷键说明

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