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

📄 portal.c

📁 pebble
💻 C
📖 第 1 页 / 共 3 页
字号:

	portal_table = portals[asid].virt;
	info = portals[asid].info;

	if (portal_table == NULL || info == NULL)
		error(INTERNAL_ERROR_PORTALS);

	id = sys_portal_alloc(asid, n, 0);
	/* no need to check return code here, */
	/* since sys_portal_alloc fails via error() */

	/*
	 * must flush the portal table entry to avoid overwriting the local copy
	 * in virtual memory.
	 */
        clean_cache(portals[asid].phys + id, n*sizeof(Portal));

	for (i = 0; i < n; i++) {
		portal_table[id+i] = e->p[i];
		memcpy(&info[id+i], &e->info[i], sizeof(Port_Info));
		info[id+i].template = strdup(e->info[i].template);
		if (info[id+i].mem != NULL)
			aligned_incref((void *)info[id+i].mem);
		if (portals[asid].notify_id > 0) {
			strlcpy(template, info[id+i].template, NAMELEN);
			call_portal(portals[asid].notify_id, id+i, template);
		}
	}

	/*
	 * must flush the portal table entry to avoid overwriting the local copy
	 * in virtual memory.
	 */
        clean_cache(portals[asid].virt + id, n*sizeof(Portal));
	/* must flush again, since calling clean_cache caused caching of */
	/* a portion of the portal table! */
        clean_cache(portals[asid].phys + id, sizeof(Portal));

	return id;
}


/*
 * Return the magic constant embedded in portal "id" of the calling domain.
 */
int
sys_portal_magic(int caller_asid, int id, uint install_2up)
{
	Portal *portal_table;
	Port_Info *info;
	int asid;

	DIAG(PORTAL_DIAG, ("sys_portal_magic for asid=%d id=%d 2u=%d\n",
		caller_asid, id, install_2up));

        if (id < 0 || id >= NPORTALS)
		error(INVALID_PORTAL_NUMBER);

	if (install_2up) {
		asid = get_caller_asid(2);
		if (asid < 0)
			error(GET_CALLER);
	} else
		asid = caller_asid;

	portal_table = portals[asid].virt;
	info = portals[asid].info;

	if (portal_table == NULL || info == NULL)
		error(INTERNAL_ERROR_PORTALS);

	if (portal_table[id] == bad_portal)
		error(INVALID_PORTAL_NUMBER);

	DIAG(PORTAL_DIAG, ("sys_portal_magic(%d,%d) returns %08x\n",
		id, install_2up, info[id].constant));

	return info[id].constant;
}


/*
 * Clone a group of "n" consecutive portals starting at portal "orig_id" into
 * the portals table of the calling domain (if "install_2up" is zero) or
 * into the portals * table of the domain which called the calling domain
 * (if "install_2up" is * not zero).
 * The embedded constant in the portals is changed to "c".
 * The group of cloned portals must be either undefined or have an embedded
 * constant. If they do not have an embdded constant, it is an error.
 * "n" must be a power of 2.
 * The cloned portals are either stored starting at portal number "id",
 * if "id" is positive, or we call portal_alloc() to allocate the new "n"
 * portals.
 *
 * Return the portal number of the first cloned portal.
 */
int
sys_portal_clone(int caller_asid, int id, int orig_id, int n, int c,
	uint install_2up)
{
	int i, install_asid, new_id, ndefined, tot_len, len, offset;
	Port_Info *info;
	Portal *portal_table, mem;
	char template[NAMELEN];
	char *phys_addr;
	int *gen_li_2inst(int *p, int rd, int val);

	DIAG(PORTAL_DIAG,
("sys_portal_clone for asid=%d id=%d orig_id=%d n=%d c=%d install_2up=%d\n",
		caller_asid, id, orig_id, n, c, install_2up));

	if (n < 1 || n >= NPORTALS)
		error(INVALID_PORTAL_SET_SIZE);

	if (orig_id <= LAST_PORTAL || (orig_id + n) >= NPORTALS)
		error(INVALID_PORTAL_NUMBER);

	if (install_2up) {
		install_asid = get_caller_asid(2);
		if (install_asid < 0)
			error(GET_CALLER);
	} else
		install_asid = caller_asid;

	portal_table = portals[install_asid].virt;
	info = portals[install_asid].info;

	if (portal_table == NULL || info == NULL)
		error(INTERNAL_ERROR_PORTALS);

	/* check that the existing set of portals */
	ndefined = tot_len = 0;
	for (i = 0; i < n; i++) {
		if (portal_table[orig_id+i] == bad_portal)
			continue;
		if (info[orig_id+i].owner != caller_asid)
			error(NOT_OWNER);
		if (info[orig_id+i].const_offset == 0)
			error(NO_CONSTANT);
		if (info[orig_id+i].len == 0)
			error(INVALID_PORTAL_LEN);
		ndefined++;
		tot_len += info[orig_id+i].len;
	}

	if (ndefined == 0)
		error(NO_DEFINED_PORTALS);

	/* allocate new portals */
	if (id < 0) {
		new_id = sys_portal_alloc(install_asid, next_power2(n), 0);
		/* no need to test returned portal number here, */
		/* since sys_portal_alloc() returns with error() */

	} else	if (id == 0 || (id + n) >= NPORTALS) {
		new_id = -1;	/* to make gcc happy */
		error(INVALID_PORTAL_NUMBER);
	} else	{
		/* id > 0 */
		/* verify that the portals in this range are valid */
		new_id = id;
		for (i = 0; i < n; i++) {
			if (portal_table[new_id+i] != bad_portal)
				error(PORTAL_DEFINED);
			if (info[new_id+i].owner != 0 &&
			    info[new_id+i].owner != caller_asid)
				error(NOT_OWNER);
		}
	}

	/*
	 * must flush the portal table entry to avoid overwriting the local copy
	 * in virtual memory.
	 */
        clean_cache(portals[install_asid].phys + new_id, n*sizeof(Portal));

	/* we prefer to allocate a single area for all cloned portals */
	if ((tot_len * sizeof(int)) < MAX_PORTAL_LEN)
		mem = (int *)aligned_malloc(tot_len * sizeof(int));
	else
		mem = NULL;
	offset = 0;

	/* now clone the portals */
	for (i = 0; i < n; i++) {
		info[new_id+i] = info[orig_id+i];
		info[new_id+i].constant = c;
		info[new_id+i].owner = caller_asid;
		info[new_id+i].template =
			strdup(info[orig_id+i].template);
		if (portal_table[orig_id+i] == bad_portal) {
			portal_table[new_id+i] = bad_portal;
			continue;
		}

		/* clone portal code */
		len = info[orig_id+i].len;
		if (mem != NULL) {
			info[new_id+i].mem = mem;
			info[new_id+i].code = mem + offset;
			/* 2nd and later cloned portals have to increase */
			/* the reference count */
			if (offset != 0)
				aligned_incref(mem);
			offset += len;
		} else	{
			info[new_id+i].mem = info[new_id+i].code =
				(int *)aligned_malloc(len*sizeof(int));
		}

		memcpy((char *)info[new_id+i].code,
			(char *)info[orig_id+i].code,
			len * sizeof(int));
		gen_li_2inst(info[new_id+i].code + info[new_id+i].const_offset,
			     info[new_id].c_reg, c);

		if (mem == NULL) {
			/* flush single cloned portal to physical memory */
			phys_addr = (char *)v2p(info[new_id+i].code);
			clean_cache(phys_addr, len*sizeof(int));
			clean_cache(info[new_id+i].code, len*sizeof(int));
		}

		/* install cloned portal in portals table */
		portal_table[new_id+i] = v2p(info[new_id+i].code);
		if (portals[install_asid].notify_id > 0) {
			strlcpy(template, info[orig_id+i].template, NAMELEN);
			call_portal(portals[install_asid].notify_id, new_id+i,
				template);
		}
	}

	/* flush the group of cloned portals to physical memory */
	if (mem != NULL) {
		phys_addr = (char *)v2p(mem);
		clean_cache(phys_addr, tot_len*sizeof(int));
		clean_cache(mem, tot_len*sizeof(int));
	}

        /*
         * must flush the cache for the portal table, since we access it through
         * cached physical memory.
         */
        clean_cache(portals[install_asid].virt + new_id, n*sizeof(Portal));
        /* must flush again, since calling clean_cache caused caching of */
        /* a portion of the portal table! */
        clean_cache(portals[install_asid].phys + new_id, n*sizeof(Portal));

        DIAG(PORTAL_DIAG, ("cloned %d portals starting at %d in asid %d\n",
		n, new_id, install_asid));

	return new_id;
}


int
sys_portal_notify(int caller_asid, int (*notify)())
{
	int id;
	char template[NAMELEN];
	vlong save[S_REGS];

	DIAG(PORTAL_DIAG, ("sys_portal_notify for asid=%d notify=%p\n", caller_asid, notify));

	if (portals[caller_asid].notify_id > 0)
		error(NOTIFICATION_DEFINED);

	if (get_caller(1, save) < 0)
		error(GET_CALLER);

	strlcpy(template, "spaiii", NAMELEN);
	id = new_portal(ASID_PORTAL, -1, caller_asid, save, template, 0, notify);
	if (id < 0)
		error(NOTIFICATION_FAILED);
	portals[caller_asid].notify_id = id;

	return id;
}


/*
 * Portal mananger initialization thread.
 * Note that parameter passing to the scheduler is non-standard.
 * The first parameter (int argc position) is the address of the portal table.
 */
int main(int argc, char *argv[])
{
	int **base;
	vlong save[S_REGS];
	int *my_epilog, portal_len, const_offset, c_reg;
	Portal *portal_table;
	Port_Info *info;

	base = (int **)argc;

	/* verify that we are running in user mode with interrupts disabled */ 
	if (!check_psw(1,0)) {
		DIAG(PORTAL_DIAG, ("portal manager: invalid processor status: %08lx\n",
			get_psw()));
		task_exit(1);
	}

	printf("portal manager is active. portal table at %p\n", base);

	DIAG(PORTAL_DIAG, ("Portal manager status=%08x\n", (uint)get_psw()));

	if (base == NULL)
		panic("invalid portal table base address");
	if (get_asid() != ASID_PORTAL)
		panic("portal manger running in an invalid ASID");

	portal_table = (Portal *)((ulong)base + IO_BASE);
	portals[ASID_PORTAL].virt = portal_table;
	portals[ASID_PORTAL].phys = (Portal *)PA_TO_KVA0((ulong)base);
	DIAG(PORTAL_DIAG, ("portal table phys=%p virt=%p\n",
		portals[ASID_PORTAL].phys, portals[ASID_PORTAL].virt));
	info = (Port_Info *)calloc(NPORTALS+NEXCPT, sizeof(Port_Info));
	if (info == NULL)
		panic("calloc owner table failed");
	portals[ASID_PORTAL].info = info;

	bad_portal = get_symbol("low_bad_portal");
	bad_excpt = get_symbol("low_bad_excpt");
	bad_win_call = get_symbol("low_bad_win_call");
	bad_win_rtn = get_symbol("low_bad_win_rtn");
	thr_stack_overflow = get_symbol("sys_thr_stack_overflow");
	ptable_level1 = get_symbol("ptable_level1");
	log = get_symbol("log");
	excpt_stack_sp = (ulong)get_symbol("excpt_stack_sp");
	excpt_stack_tlbhi = (ulong)get_symbol("excpt_stack_tlbhi");
	excpt_stack_tlblo0 = (ulong)get_symbol("excpt_stack_tlblo0");
	if ((int)bad_portal == -1 || (int)bad_excpt == -1 || (int)log == -1 ||
	    (int)bad_win_call == -1 || (int)bad_win_rtn == -1 ||
	    (int)thr_stack_overflow == -1 || (int)ptable_level1 == -1 ||
	    (int)excpt_stack_sp == -1 || (int)excpt_stack_tlbhi == -1 ||
	    (int)excpt_stack_tlblo0 == -1)
		panic("failed to get symbol value from nucleus");

	/* get the portal manager's own data */
	if (get_caller(0, save) < 0)
		panic("get_caller");
	my_epilog = (int *)
		((char *)get_domain_entry(get_asid()) + 2 * sizeof(int));

	/*
	 * must flush the portal table in cached physical memory to since we
	 * access it via an I/O window (an address alias).
	 */
        clean_cache(portals[ASID_PORTAL].phys, NPORTALS*sizeof(Portal));

	/* create the portals of the portal manager */
	info[SYS_PORTAL_ALLOC].code = info[SYS_PORTAL_ALLOC].mem =
		gen_portal(save, &sys_portal_alloc,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_ALLOC] =
		v2p(info[SYS_PORTAL_ALLOC].code);

	info[SYS_PORTAL_NAME].code = info[SYS_PORTAL_NAME].mem =
		gen_portal(save, &sys_portal_name,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_NAME] =
		v2p(info[SYS_PORTAL_NAME].code);

	info[SYS_PORTAL_OPEN].code = info[SYS_PORTAL_OPEN].mem =
		gen_portal(save, &sys_portal_open,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_OPEN] =
		v2p(info[SYS_PORTAL_OPEN].code);

	info[SYS_PORTAL_CREATE].code = info[SYS_PORTAL_CREATE].mem =
		gen_portal(save, &sys_portal_create,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_CREATE] =
		v2p(info[SYS_PORTAL_CREATE].code);

	info[SYS_PORTAL_CREATE_CHILD].code = info[SYS_PORTAL_CREATE_CHILD].mem =
		gen_portal(save, &sys_portal_create_child,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_CREATE_CHILD] =
		v2p(info[SYS_PORTAL_CREATE_CHILD].code);

	info[SYS_PORTAL_CREATE0].code = info[SYS_PORTAL_CREATE0].mem =
		gen_portal(save, &sys_portal_create0,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_CREATE0] =
		v2p(info[SYS_PORTAL_CREATE0].code);

	info[SYS_PORTAL_DELETE].code = info[SYS_PORTAL_DELETE].mem =
		gen_portal(save, &sys_portal_delete,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_DELETE] =
		v2p(info[SYS_PORTAL_DELETE].code);

	info[SYS_GEN_PORTAL_TABLE].code = info[SYS_GEN_PORTAL_TABLE].mem =
		gen_portal(save, &sys_gen_portal_table,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, A0, 0, 0, 0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_GEN_PORTAL_TABLE] =
		v2p(info[SYS_GEN_PORTAL_TABLE].code);

	info[SYS_PORTAL_NOTIFY].code = info[SYS_PORTAL_NOTIFY].mem =
		gen_portal(save, &sys_portal_notify,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_NOTIFY] =
		v2p(info[SYS_PORTAL_NOTIFY].code);

	info[SYS_PORTAL_MAGIC].code = info[SYS_PORTAL_MAGIC].mem =
		gen_portal(save, &sys_portal_magic,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_MAGIC] =
		v2p(info[SYS_PORTAL_MAGIC].code);

	info[SYS_PORTAL_CLONE].code = info[SYS_PORTAL_CLONE].mem =
		gen_portal(save, &sys_portal_clone,
		my_epilog, STACK_SHARED, SAVE_PARTIAL, NULL, 0, 0, 0, A0,
		0, 0, 0, &portal_len, &const_offset, &c_reg);
	portal_table[SYS_PORTAL_CLONE] =
		v2p(info[SYS_PORTAL_CLONE].code);

	DIAG(PORTAL_DIAG, ("portal manager before portal table clean_cache\n"));
	/*
	 * must flush the cache for the portal table, since we access it later
	 * via cached physical memory.
	 */
        clean_cache(portals[ASID_PORTAL].virt, NPORTALS*sizeof(Portal));
	/* must flush again, since calling clean_cache caused caching of */
	/* a portion of the portal table! */
        clean_cache(portals[ASID_PORTAL].phys, NPORTALS*sizeof(Portal));

	/* the nucleus shares the portals table witht the portals manager */
	if (sys_gen_portal_table(get_thread(), ASID_PORTAL, ASID_NUCLEUS, 0, 0)
	    == -1) 
		panic("gen_portal_table for nucleus failed:");

	/*
	 * return to initialization code.
	 * cannot just "return", since the startup code (crt0.S) calls
	 * exit when main routine terminates.
	 */
	DIAG(PORTAL_DIAG, ("portal manager before return\n"));
	call_portal(SYS_RTN_RPC);
	return(1);
}

⌨️ 快捷键说明

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