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

📄 portal.c

📁 pebble
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 
 * 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.
 *
 */

/*
 * Portal manager
 * Runs in user mode with interrupts enabled.
 *
 * Since the portal manager is the first server that is activated
 * in the system, the initialization code MUST NOT call any service
 * that is not yet defined.
 * Also, interrupts must be disabled during the initialization, since the
 * interrupt dispatcher is not active yet.
 */

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

typedef	struct	{
	Portal code;	/* virtual address of corresponding portal code */
	Portal mem;	/* starting address of memory area containing the */
			/* portal code. However, the memory may contain */
			/* multiple portals, all of which have the same */
			/* "mem" value, but different "code" values. */
	int len;	/* portal code length in words */
	uint owner;	/* the owner of the associated portal */
	char *template;	/* the portal's template */
	uint constant;	/* constant value embedded in the portal code */
	int const_offset;/* the offset (in words) of the constant in the */
			/* portal code */
	int c_reg;	/* the constant is loaded into this machine register */
} Port_Info;

/*
 * Each domain may have a private portals table.
 * The "virt" and "phys" fields in the Domain_Portals structure refer
 * to the same portals table. The portals manager accesses the table via
 * the "virt" address, while the portal code accesses the same table via
 * the "phys" address.
 *
 * The portals table contain the physical address of the portals.
 */
typedef	struct	{	/* per domain portals table */
	Portal *virt;	/* address in portal manager's address space */
			/* here we store the physical addresses of the portals */
	Portal *phys;	/* physical address in KSEG0 */
			/* this is the physical address of the virt field above */
	Port_Info *info;/* portals information */
	int notify_id;	/* notification portal ID */
	int parent_asid;/* parent domain ASID */
} Domain_Portals;

/* an element in the portals name list */
typedef	struct elem	{
	char name[NAMELEN];
	int n;
	Portal *p;
	Port_Info *info;
	struct elem *next;
} Elem;
	
static Domain_Portals portals[NASID];
static StackQ *stack_queue[NASID];

static Elem *names_list = NULL;
static int *bad_portal, *bad_excpt;
int *bad_win_call, *bad_win_rtn, *thr_stack_overflow;
int *ptable_level1;
int *log;
ulong excpt_stack_sp, excpt_stack_tlbhi, excpt_stack_tlblo0;

const char INVALID_PORTAL_NUMBER[] = "invalid portal number";
const char INVALID_PORTAL_SET_SIZE[] = "invalid portals set size";
const char INVALID_PORTAL_NAME[] = "invalid portal name";
const char INVALID_PORTAL_TEMPLATE[] = "invalid portal template";
const char INVALID_PORTAL_COMBINATION[] = "invalid combination of stack type and save type";
const char INVALID_ENTRY[] = "invalid portal entry point";
const char NOT_OWNER[] = "not the portal owner";
const char NO_DEFINED_PORTALS[] = "no defined portal in range";
const char INVALID_CALL_FRAME[] = "invalid call frame number";
const char INVALID_FRAME_CONTENTS[] = "internal error: invalid call frame contents";
const char DUP_PORTAL_NAME[] = "duplicate portal name";
const char PORTAL_OVERFLOW[] = "portal table overflow";
const char PORTAL_DEFINED[] = "portal already defined";
const char MEMORY_ALLOCATION[] = "internal error: memory allocation failed";
const char GET_CALLER[] = "internal error: get_caller failed";
const char INTERNAL_ERROR_PORTALS[] = "internal error: caller has no portals table";
const char INVALID_ASID[] = "invalid address space ID";
const char NO_PARENT_PORTALS[] = "parent domain has no portals table";
const char CHILD_HAS_PORTALS[] = "child domain has portals already";
const char NOT_PARENT[] = "not the parent of the child domain";
const char NO_WINDOW_INTERPOSE[] = "cannot interpose a portal with a window";
const char TOO_MANY_PARAMETERS[] = "template has too many parameters";
const char NOTIFICATION_FAILED[] = "portal notification failed due to internal error";
const char NOTIFICATION_DEFINED[] = "portal notification function already defined";
const char NO_CONSTANT[] = "portal has no embedded constant";
const char INVALID_PORTAL_LEN[] = "internal error: invalid portal code length";

/* Translate virtual address to physical address */
Portal
v2p(void *v)
{
	return (Portal)PA_TO_KVA0((ulong)virt2phys(v));
}


char
tolower(char c)
{
	if (c >= 'A' && c <= 'Z')
		return 'a' + (c - 'A');
	else
		return c;
}

/* Note: "name" may be not NUL terminated */
static Elem *
portal_lookup(const char *name)
{
	Elem *p;
	char area[NAMELEN];

	if (name == NULL || name[0] == '\0')
		error(INVALID_PORTAL_NAME);

	strlcpy(area, name, NAMELEN);
	for (p = names_list; p != NULL; p = p->next)
		if (strcmp(p->name, area) == 0)
			return p;

	return NULL;
}


/*
 * Note: we do not have to check input parameters, since they were checked
 * by sys_gen_portal_table
 */
static void
gen_interpose(int parent_asid, int child_asid, int interpose_id)
{
	int i;

	DIAG(PORTAL_DIAG, ("gen_interpose: parent_asid=%d child_asid=%d interpose_id=%d\n",
		parent_asid, child_asid, interpose_id));

	if (interpose_id <= 0 || interpose_id >= NPORTALS ||
	    portals[parent_asid].virt[interpose_id] == bad_portal)
		error(INVALID_PORTAL_NUMBER);

	if (portals[parent_asid].info == NULL ||
	    portals[child_asid].info == NULL)
		error(INTERNAL_ERROR_PORTALS);

	if (portals[parent_asid].info[interpose_id].owner != parent_asid)
		error(NOT_OWNER);

	/* interpose the interpose_id portal on all existing portal in */
	/* child_asid */
	for (i = 0; i < NPORTALS; i++) {
		/* allow the default SYS_FORK & SYS_SBRK until we handle them */
		/* correctly */
		if (i == SYS_FORK || i == SYS_SBRK)
			continue;
		if (portals[child_asid].info[i].owner != 0)
			portals[child_asid].info[i].owner = parent_asid;
		if (portals[child_asid].virt[i] == bad_portal)
			continue;
		if (strchr(portals[child_asid].info[i].template, 'w') > 0 ||
		    strchr(portals[child_asid].info[i].template, '>') > 0 ||
		    strchr(portals[child_asid].info[i].template, '=') > 0)
			error(NO_WINDOW_INTERPOSE);
		portals[child_asid].virt[i] =
			portals[parent_asid].virt[interpose_id];
		/* overwriting an existing portal */
		if (portals[child_asid].info[i].mem != NULL)
			aligned_decref(portals[child_asid].info[i].mem);
		portals[child_asid].info[i].code =
			portals[parent_asid].info[interpose_id].code;
		portals[child_asid].info[i].mem =
			portals[parent_asid].info[interpose_id].mem;
		aligned_incref(portals[child_asid].info[i].mem);
	}
}

/*
 * Allocate child domain's portal table.
 * Return pointer to child's portals table in KSEG0.
 */
int
sys_gen_portal_table(Thread *t, int parent_asid, int child_asid, uint is_copy, int interpose_id)
{
	int i;

	DIAG(PORTAL_DIAG,
	("sys_gen_portal_table: thread=%p parent=%d child=%d is_copy=%d interpose_id=%d\n", t, parent_asid, child_asid, is_copy, interpose_id));

	if (parent_asid < 0 || parent_asid >= NASID ||
	    child_asid < 0 || child_asid >= NASID)
		error(INVALID_ASID);

	if (portals[parent_asid].virt == NULL ||
	    portals[parent_asid].info == NULL)
		error(NO_PARENT_PORTALS);

	if (portals[child_asid].virt != NULL ||
	    portals[child_asid].info != NULL)
		error(CHILD_HAS_PORTALS);

	if (is_copy) {
		portals[child_asid].virt =
		  (Portal *)aligned_malloc((NPORTALS+NEXCPT)*sizeof(Portal));
		portals[child_asid].info =
			(Port_Info *)calloc(NPORTALS+NEXCPT, sizeof(Port_Info));
		if (portals[child_asid].virt == NULL ||
		    portals[child_asid].info == NULL)
			error(MEMORY_ALLOCATION);
		portals[child_asid].phys =
			(Portal *)v2p(portals[child_asid].virt);
		/* must flush the cache to avoid late writes to the same */
		/* physical memory */
		clean_cache(portals[child_asid].phys,
			(NPORTALS+NEXCPT)*sizeof(Portal));
		memcpy(portals[child_asid].virt, portals[parent_asid].virt,
			(NPORTALS+NEXCPT)*sizeof(Portal));
		memcpy(portals[child_asid].info, portals[parent_asid].info,
			(NPORTALS+NEXCPT)*sizeof(Port_Info));
		/* copy portal templates. Note: strdup(NULL) == NULL */
		for (i = 0; i < NPORTALS+NEXCPT; i++)
			portals[child_asid].info[i].template =
				strdup(portals[parent_asid].info[i].template);
		portals[child_asid].parent_asid = parent_asid;
		portals[child_asid].notify_id = 0;

		if (interpose_id > 0)
			gen_interpose(parent_asid, child_asid, interpose_id);

		/* must flush the cache to expose new portal table */
		clean_cache(portals[child_asid].virt,
			(NPORTALS+NEXCPT)*sizeof(Portal));
		/* must flush again, since clean_cache caused caching of */
		/* a portion of the portals table! */
		clean_cache(portals[child_asid].phys,
			(NPORTALS+NEXCPT)*sizeof(Portal));
	} else	{
		/* share portals table between parent and child */
		portals[child_asid] = portals[parent_asid];
	}

	/* increase reference count for portals */
	for (i = 0; i < (NPORTALS+NEXCPT); i++)
		if (portals[child_asid].info[i].mem != NULL)
			aligned_incref(portals[child_asid].info[i].mem);

	DIAG(PORTAL_DIAG,
		("sys_gen_portal_table returns %p\n",
		portals[child_asid].phys));

	return (int)portals[child_asid].phys;
}

/*
 * Create a set of n consecutive portals in caller_asid domain
 * or in parent domain of the caller domain,
 * where the first portal is aligned on "n" boundary.
 * The portals are allocated from the file descriptors area of the portals table.
 */
int
sys_portal_alloc(int caller_asid, int n, uint install_2up)
{
	int id, i, asid, m;
	Portal *portal_table;
	Port_Info *info;
	uint found = FALSE;

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

	if (caller_asid < 0 || caller_asid >= NASID)
		error(INVALID_ASID);
	
	/* ensure that we do not step on pre-defined file descriptors */
	/* i.e. define portal #66 when #67 (write on fd #1) is defined. */
	if (n == 1)
		m = 2;
	else
		m = n;

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

	assert(asid >= 0 && asid < NASID);

	portal_table = portals[asid].virt;
	info = portals[asid].info;
	if (portal_table == NULL || info == NULL)
		error(INTERNAL_ERROR_PORTALS);

	/* note: m is the size of the group of available portals */
	/* that we are looking for, from which n are actually allocated. */
	for (id = PORTAL_FD_START; (id + m) <= NPORTALS; id += n) {
		for (i = 0; i < m; i++)
			if (portal_table[id+i] != bad_portal ||
			    info[id+i].owner != 0)
				break;
		if (i >= m) {
			/* which means that we found a set of "m" free portal */
			/* entries */
			found = TRUE;
			break;
		}
	}

	/* The "found" flag denotes that we have "m" consecutive entries. */
	/* We require "m" entries although we need only "n" entries to avoid */
	/* allocating the last portal entry (NPORTALS-1) again and again */
	/* when n=1 and m=2. */
	if (!found)
		error(PORTAL_OVERFLOW);

	assert((id + n) <= NPORTALS);
	for (i = 0; i < n; i++) {
		assert(info[id+i].owner == 0);
		info[id+i].owner = caller_asid;
	}

	DIAG(PORTAL_DIAG, ("sys_portal_alloc returns %d for asid=%d\n",
		id, asid));

	return id;
}


/* note: "name" may not be NUL terminated! */
int
sys_portal_name(int asid, int id, const char *name, int n)
{
	Elem *e;
	int ndefined = 0;
	int i;
	Portal *portal_table;
	Port_Info *info;

	DIAG(PORTAL_DIAG, ("sys_portal_name: asid=%d id=%d name=%s n=%d\n",
		asid, id, name, n));

	if (n < 1 || !is_power2(n))
		error(INVALID_PORTAL_SET_SIZE);

	if (id < PORTAL_FD_START || (id + n) >= NPORTALS)
		error(INVALID_PORTAL_NUMBER);

        if (name == NULL || param_check(name, NAMELEN, 1) < 0 ||
	    name[0] == '\0')
		error(INVALID_PORTAL_NAME);

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

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

	for (i = 0; i < n; i++) {
		/* anybody can name a portal that is visible to them */
		/* the following piece of code is depreciated */
		/* if (info[id+i].owner != asid) error(NOT_OWNER); */
		if (portal_table[id+i] != bad_portal)
			ndefined++;
	}

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

	if (portal_lookup(name) != NULL)
		error(DUP_PORTAL_NAME);

	/* create portal name element */
	e = (Elem *)malloc(sizeof(Elem));
	if (e == NULL)
		error(MEMORY_ALLOCATION);
	e->info = (Port_Info *)calloc(n, sizeof(Port_Info));
	e->p = (Portal *)calloc(n, sizeof(Portal));
	if (e->info == NULL || e->p == NULL)
		error(MEMORY_ALLOCATION);

	strlcpy(e->name, name, NAMELEN);
	e->n = n;
	memcpy(e->info, &info[id], n*sizeof(Port_Info));
	memcpy(e->p, &portal_table[id], n*sizeof(Portal));
	for (i = 0; i < n; i++)
		e->info[i].template = strdup(info[id+i].template);

	e->next = names_list;
	names_list = e;

	DIAG(PORTAL_DIAG, ("sys_portal_name: returning %d\n", id));

	return id;
}

/*
 * This routine is called only for parameter type 'c' and 't'.
 * These parameters may be placed on the stack too (as arguments 4 and 5).
 * If they are placed on the stack, then no other parameter (of types 
 * other than 'c' or 't') may be placed in argument positions 4 and 5,
 * since we change the stack pointer.
 */
static void
check_synthetic_arg(int id, const int i, const char *template)
{
	if (i >= MAX_PORTAL_ARGS)
		error(INVALID_PORTAL_TEMPLATE);
	if (i >= NREG_ARGS) {
		if ((template[i] != 'c' && template[i] != 't') ||
		    (template[NREG_ARGS] != 'c' &&
		     template[NREG_ARGS] != 't') ||
		    (template[NREG_ARGS+1] != 'c' &&
		     template[NREG_ARGS+1] != 't' &&
		     template[NREG_ARGS+1] != '\0'))
			error(INVALID_PORTAL_TEMPLATE);
	}
}

/*
 * Install a new portal to domain "caller_asid" as portal #id in domain
 * "install_asid".
 *
 * Portal is generated with the given template, constant value and entry point.
 */
static int
new_portal(int install_asid, int id, int server_asid, vlong save[],

⌨️ 快捷键说明

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