📄 portal.c
字号:
/*
* 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 + -