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

📄 code.c

📁 pebble
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 
 * Copyright 1999, 2000, 2001, 2002 Lucent Technologies Inc.
 * All Rights Reserved.
 * Information Sciences Research Center, Bell Labs.
 *
 * LUCENT TECHNOLOGIES DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE 
 * OR THE SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The
 * software is provided "as is" without expressed or implied warranty 
 * of any kind.
 *
 * These notices must be retained in any copies of any part of this
 * software.
 *
 */

/*
 *	Dynamic code generation
 *
 *	Code generation must avoid pipeline hazards.
 *	Specific hazards for RM7000:
 *	setting EPC must followed by at least 4 integer instructions before ERET
 *	setting CP0 registers must be followed by at least 4 integer
 *		instructions before TLBWI.
 *
 *	Important:
 *	If rm5230 is defined, then r5000 is also defined!
 */

#include "string.h"
#include "machine/cpu.h"
#include "diag.h"
#include "pebble.h"
#include "mem.h"
#include "log.h"
#include "op.h"
#include "../port/portal.h"

#define	NPORTAL_RETURNS	18	/* number of different return portals */

/* processor depenent constants for avoiding pipeline hazards */
#if	#cpu(rm7000)
#define	MTC0_TO_TLB_OP	4	/* TLBR, TLBP, TLBWI */
#define	TLBR_TO_MFC0	4
#define	TLBP_TO_MFC0	4
#define	TLBW_TO_BRANCH	8
#define	TLBW_TO_ACCESS	4
#else
#if	#cpu(rm5230)
#define	MTC0_TO_TLB_OP	2	/* TLBR, TLBP, TLBWI */
#define	TLBR_TO_MFC0	2
#define	TLBP_TO_MFC0	2
#define	TLBW_TO_BRANCH	2
#define	TLBW_TO_ACCESS	2
#else 
#if	#cpu(r5000)
#define	MTC0_TO_TLB_OP	2	/* TLBR, TLBP, TLBWI */
#define	TLBR_TO_MFC0	3
#define	TLBP_TO_MFC0	3
#define	TLBW_TO_BRANCH	4
#define	TLBW_TO_ACCESS	5
#else
#if	defined(Cobalt)
#define	MTC0_TO_TLB_OP	2	/* TLBR, TLBP, TLBWI */
#define	TLBR_TO_MFC0	2
#define	TLBP_TO_MFC0	2
#define	TLBW_TO_BRANCH	2
#define	TLBW_TO_ACCESS	2
#else
#error	"invalid CPU type"
#endif
#endif
#endif
#endif

#ifdef	Cobalt
/* new calling sequence: every parameter takes 8 bytes on the stack */
/* pass double word parameters in a single register */
#define SAVEREGS	32
#define	PARAM_SIZE	8
#else
/* old calling sequence */
/* pass double word parameters in a register pair */
#define	SAVEREGS	16
#define	PARAM_SIZE	4
#endif

static int *portal_code = NULL;	/* portals are created in this area */
			/* then copied to dynamically allocated memory */

/*
 * Generate a jump instruction.
 * Note that the buffer address (p) is in virtual memory,
 * while the actual portal code will be executed in kernel mode with physical
 * addresses.
 */
static int *
gen_j(int *p, int *addr)
{
	int *phys;

	phys = PA_TO_KVA0((ulong)virt2phys(p));
	if (((ulong)phys & JUMP_HI_MASK) !=
	    ((ulong)addr & JUMP_HI_MASK))
		panic("cannot generate jump instruction outside the region");
	if ((ulong)p & 03)
		panic("cannot generate jump intruction to unaligned address");
	*p++ = J((ulong)addr >> 2);

	return p;
}


static int *
gen_li(int *p, int rd, int val)
{
	if (val == 0)
		*p++ = ADDIU(rd,ZERO,0);
	else if ((val & IMMASK) == 0)
		/* low 16 bits are zero */
		*p++ = LUI(rd, (val >> 16));
	else if ((val & SEXTMASK) == SEXTMASK || (val & SEXTMASK) == 0)
		/* a 16 bit value sign extended to 32 bits */
		*p++ = ADDIU(rd,ZERO,val);
	else if ((val & IMMASK) == val)
		/* 16 high order bits are zero */
		*p++ = ORI(rd,ZERO,val);
	else	{
		/* no luck; must generate the value with two instructions */
		*p++ = LUI(rd,(val >> 16));
		*p++ = ORI(rd,rd,(val & IMMASK));
	}

	return p;
}


/* generate a constant in two instructions. necessary for cloning */
int *
gen_li_2inst(int *p, int rd, int val)
{
	*p++ = LUI(rd,(val >> 16));
	*p++ = ORI(rd,rd,(val & IMMASK));

	return p;
}

static int *
gen_lw(int *p, int rd, ulong addr, int rs)
{
	int hi_addr;

	if (rd == rs)
		panic("invalid register input to gen_lw");

	hi_addr = addr >> 16;
	/* will the low-order 16 bits of the address casue a sign extension? */
	if (addr & 0x8000)
		hi_addr -= 0xffff;
	*p++ = LUI(rd, hi_addr); 
	if (rs != ZERO)
		*p++ = ADD(rd, rd, rs);
	*p++ = LW(rd, addr & IMMASK, rd);

	return p;
}

#if	0
/* not used (yet) */
static int *
gen_la(int *p, int rd, int addr)
{
	return gen_li(p, rd, addr);
} 
#endif


/*
 * Probe if TLB contains an entry matching the virtual address.
 * If entry is found, erase it from TLB.
 * The virtual address must be in the format of the TLBHI register
 * (including ASID in lower bits).
 * The register "addr_reg" is clobbered by this routine.
 * The ASID field in TLBHI register may be set to zero by this routine
 * and should be restored to its previous value.
 *
 * C0_INDEX must cleared to zero if we call gen_restrpc after this routine.
 */
static int *
gen_tlb_probe_erase(int *p, int addr_reg, int *label)
{
	int *old_p;

	*p++ = DMTC0(addr_reg, C0_TLBHI);
	*p++ = MTC0(ZERO, C0_PAGEMASK);
	old_p = p;

	/* MTC0 must be followed by at least MTC0_TO_TLB_OP integer */
	/* instructions before a TLBP */
	while ((p - old_p) < MTC0_TO_TLB_OP)
		*p++ = NOP;

	*p++ = TLBP;
	old_p = p;

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

	*p++ = MFC0(addr_reg, C0_INDEX);
	*p++ = DMTC0(ZERO, C0_TLBHI);
	*p++ = DMTC0(ZERO, C0_TLBLO0);
	*p++ = DMTC0(ZERO, C0_TLBLO1);
	old_p = p;
	*p++ = BLTZ(addr_reg, label - (p+1));
	*p++ = NOP;

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

	*p++ = TLBWI;
	old_p = p;

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

	return p;
}


/*
 * Generate code to fill the portal number and the from ASID fields
 * of the current log record. This code does not move the log record
 * pointer. We assume that gen_write_log() will be called later to
 * generate the rest of the log record write code.
 * This code uses registers T0 and T1.
 * "portal_no" is the register containing the portal number of the currently
 * active portal.
 */
static int *
gen_write_log_portal(int *start, int portal_no)
{
	int *p = start;

	*p++ = MFC0(T1, C0_TLBHI);
	p = gen_lw(p, T0, ((ulong)log) + LOG_DESC_HEAD*4, ZERO);
	*p++ = SW(portal_no, LOG_ENTRY_PORTAL*4, T0);
	*p++ = ANDI(T1, T1, TLBHI_PIDMASK);
	*p++ = SW(T1, LOG_ENTRY_FROM_ASID*4, T0);

	return p;
}


/*
 * Generate code to fill the rest of the log record and advance the log
 * record pointer.
 * This code uses registers T0 through T4 (inclusive).
 */
static int *
gen_write_log(int *start, int treg, int base, int to_asid, int val1, int val2)
{
	int *p = start;

	p = gen_li(p, T0, (ulong)log);
        *p++ = LW(T1, LOG_DESC_HEAD*4, T0);
        *p++ = LW(T2, LOG_DESC_LOW*4, T0);
        *p++ = LW(T3, LOG_DESC_HIGH*4, T0);
        *p++ = MFC0(T4, C0_COUNT);
        *p++ = SW(to_asid, LOG_ENTRY_TO_ASID*4, T1);
        *p++ = SW(treg, LOG_ENTRY_THREAD*4, T1);
        *p++ = SW(base, LOG_ENTRY_CALL_SP*4, T1);
        *p++ = SW(SP, LOG_ENTRY_USER_SP*4, T1);
        *p++ = SW(val1, LOG_ENTRY_P0*4, T1);
        *p++ = SW(val2, LOG_ENTRY_P1*4, T1);
        *p++ = SW(T4, LOG_ENTRY_TIME*4, T1);
        *p++ = ADDIU(T1, T1, LOG_ENTRY_FIELDS*4);
        *p++ = SLTU(T4, T1, T3);
        *p++ = MOVZ(T1, T2, T4);
        *p++ = SW(T1, LOG_DESC_HEAD*4, T0);

	return p;
}


/*
 *	Generate portal return code
 *	Returned value: physical address of return portal
 */
static int *
gen_portal_rtn(int treg, int base, PortalStack stack_type,
	PortalSave stack_save, uint is_window)
{
	int *p, *old_p, *start, *phys_start;
	int len, i;
	int *label6, *label7;
	static int *return_code = NULL;

	DIAG(PORTAL_DIAG, ("gen_portal_rtn: stack_type=%d stack_save=%d is_window=%d\n",
		stack_type, stack_save, is_window));

	if (return_code == NULL)
		return_code = (int *)malloc(MAX_PORTAL_LEN);

	/* we must repeat code generation twice in order to compute */
	/* forward branch offsets! */
	label6 = label7 = return_code;	/* for first iteration */

	for (i = 0; i <= 1; i++) {
		p = return_code;

		if (PORTAL_LOG) {
			p = gen_li(p, T7, -1);
			*p++ = LW(T6, S_TLBHI*8, base);
			p = gen_write_log_portal(p, T7);
			*p++ = ANDI(T6, T6, TLBHI_PIDMASK);
			p = gen_write_log(p, treg, base, T6, V0, V1);
		}

		if (is_window) {
			*p++ = LD(T7, S_WIN_COUNT*8, base);
			*p++ = LB(T6, 0, T7);
			*p++ = LD(T8, S_WIN_VADDR*8, base);
			*p++ = BNE(T6, ZERO, label7 - (p+1));
			*p++ = ADDIU(T6, T6, -1);
			p = gen_j(p, bad_win_rtn);
			*p++ = NOP;

			label7 = p;

			*p++ = BNE(T6, ZERO, label6 - (p+1));
			*p++ = SB(T6, 0, T7);
			/* must clear TLB entry of a window with a zero */
			/* access counter */
			*p++ = LB(T5, NASID, T7);
			p = gen_li(p, T4, 1);
			/* was it loaded into the TLB at all? */
			*p++ = BNE(T5, ZERO, label6 - (p+1));
			*p++ = SB(T4, NASID, T7);
			p = gen_tlb_probe_erase(p, T8, label6);
		}

		label6 = p;

		if (stack_type == STACK_QUEUE) {
			/* return stack to queue */
			*p++ = LW(T3, THR_STACK_Q*4, treg);
			*p++ = LW(T5, THR_STACK_DESC*4, treg);
			*p++ = SW(T3, STACK_DESC_NEXT*4, T5);
			*p++ = SW(T5, STACK_Q_HEAD*4, T3);
		}

		*p++ = LD(T2, S_TLBHI*8, base);
		*p++ = LW(T4, S_STATUS*8, base);
		*p++ = LD(T3, S_TLBLO0*8, base);
		*p++ = LD(T5, S_EPC*8, base);
		*p++ = MTC0(ZERO, C0_INDEX);
		*p++ = DMTC0(T2, C0_TLBHI);
		*p++ = DMTC0(T3, C0_TLBLO0);
		*p++ = DADDIU(T6, T3, TLBLO0toLO1);
		*p++ = DMTC0(T6, C0_TLBLO1);
		*p++ = MTC0(ZERO, C0_PAGEMASK);
		*p++ = MTC0(T4, C0_STATUS);
		*p++ = DMTC0(T5, C0_EPC);
		*p++ = LW(T1, S_STACK_DESC*8, base);
		*p++ = LW(T2, S_STACK_Q*8, base);
		*p++ = LW(T3, S_PORTAL_TBL*8, base);
		*p++ = LD(T4, S_PTE*8, base);

		*p++ = TLBWI;
		old_p = p;

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

		*p++ = SW(T1, THR_STACK_DESC*4, treg);
		*p++ = SW(T2, THR_STACK_Q*4, treg);
		*p++ = SW(T3, THR_PORTAL_TBL*4, treg);
		*p++ = SD(T4, THR_PTE*4, treg);

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

		if (stack_save == SAVE_FULL) {
			*p++ = LD(T0, S_LO*8, base);
			*p++ = LD(T1, S_HI*8, base);
			*p++ = LD(AT, S_AT*8, base);
			*p++ = LD(V0, S_V0*8, base);
			*p++ = LD(V1, S_V1*8, base);
			*p++ = MTLO(T0);
			*p++ = MTHI(T1);
			*p++ = LD(A0, S_A0*8, base);
			*p++ = LD(A1, S_A1*8, base);
			*p++ = LD(A2, S_A2*8, base);
			*p++ = LD(A3, S_A3*8, base);
			*p++ = LD(T0, S_T0*8, base);
			*p++ = LD(T1, S_T1*8, base);
			*p++ = LD(T2, S_T2*8, base);
			*p++ = LD(T3, S_T3*8, base);
			*p++ = LD(T4, S_T4*8, base);
			*p++ = LD(T5, S_T5*8, base);
			*p++ = LD(T6, S_T6*8, base);
			*p++ = LD(T7, S_T7*8, base);
			*p++ = LD(T8, S_T8*8, base);
			*p++ = LD(T9, S_T9*8, base);

		}

		*p++ = DADDIU(base, base, 8*S_REGS);
		*p++ = SW(base, THR_CALL_SP*4, treg);
		*p++ = ERET;
	}

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

	len = p - return_code;
	if (len*sizeof(int) > MAX_PORTAL_LEN)
		panic("portal code overflow");
	start = (int *)aligned_malloc(len*sizeof(int));
	memcpy((char *)start, (char *)return_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));

	DIAG(PORTAL_DIAG, ("gen_portal_rtn: start at %p\n", phys_start));
	return (Portal)phys_start;
}


static int *
lookup_portal_rtn(PortalStack stack_type, PortalSave stack_save,
	uint window_reg, uchar window_type)
{
	int is_window; 
	int i;
	static int *portal_rtn[NPORTAL_RETURNS];

	/* note: '>' and '=' window types are not handled by return portal! */
	is_window = (window_reg != 0) && (window_type == 'w');

	/* convert the combination of <stack_type, stack_save, is_window> */
	/* to an index */
	i = (int)stack_type * 6 + (int)stack_save * 3 + is_window;
	if (i < 0 || i >= NPORTAL_RETURNS)
		panic("lookup_portal_rtn: invalid lookup table index");

	if (portal_rtn[i] == NULL)
		portal_rtn[i] =
		    gen_portal_rtn(K0, K1, stack_type, stack_save, is_window);

	return portal_rtn[i];
}


/*
 *	assumption: C0_INDEX is zero on entry
 *
 *	must not change register T9, which is set by the gen_pushreg routine
 */
static int *
gen_savereg(int *p, int treg, int base,
	PortalStack stack_type, PortalSave stack_save,
	uint asid_reg, uint window_reg, uchar window_type,
	int new_asid, int *last_mtc)
{
	int *start, *label, *label9, *label10;
	int i;

	if (stack_save == SAVE_FULL) {
		*p++ = SD(AT, S_AT*8, base);
		*p++ = SD(V0, S_V0*8, base);
		*p++ = SD(V1, S_V1*8, base);
		*p++ = SD(A0, S_A0*8, base);
		*p++ = MFLO(V0);
		*p++ = SD(A1, S_A1*8, base);
		*p++ = SD(A2, S_A2*8, base);
		*p++ = SD(A3, S_A3*8, base);
		*p++ = SD(T0, S_T0*8, base);
		*p++ = MFHI(V1);
		*p++ = SD(T1, S_T1*8, base);

⌨️ 快捷键说明

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