📄 portal.c
字号:
char *template, uint c, int (*entry)())
{
PortalStack stack_type = STACK_SHARED;
PortalSave stack_save = SAVE_FULL; /* to make GCC happy */
int asid_reg, const_reg, thread_reg, window_reg, bad_vaddr_reg;
uchar window_type = '\0';
int i, portal_len, const_offset, c_reg;
char *s;
Portal *portal_table;
Port_Info *info;
DIAG(PORTAL_DIAG,
("new_portal: install_asid=%d id=%d server_asid=%d save=%p\n",
install_asid, id, server_asid, save));
DIAG(PORTAL_DIAG, ("template=%s c=%08x entry=%p\n",
template, c, entry));
if (template == NULL || param_check(template, NAMELEN, 1) < 0)
error(INVALID_PORTAL_TEMPLATE);
if (entry == NULL)
error(INVALID_ENTRY);
if ((save[S_TLBHI] & TLBHI_PIDMASK) != server_asid)
error(INVALID_FRAME_CONTENTS);
portal_table = portals[install_asid].virt;
info = portals[install_asid].info;
if (portal_table == NULL || info == NULL)
error(INTERNAL_ERROR_PORTALS);
switch(tolower(template[0])) {
case 'e':
stack_type = STACK_EXCEPTION;
if (id < 0 || id >= NEXCPT)
error(INVALID_PORTAL_NUMBER);
if (portal_table[NPORTALS+id] != bad_excpt)
error(PORTAL_DEFINED);
id += NPORTALS;
break;
case 'q':
stack_type = STACK_QUEUE;
/* fall through */
case 's':
/* default stack type is STACK_SHARED */
/* must not overwrite portal #0, which must point to */
/* the undefined portal handler */
if (id == 0)
error(INVALID_PORTAL_NUMBER);
if (id < 0) {
id = sys_portal_alloc(install_asid, 1, 0);
/* no need to check return code here, */
/* since sys_portal_alloc fails via error() */
/* fix owner, since we may install portal in an */
/* unrelated domain. */
info[id].owner = server_asid;
}
if (id >= NPORTALS)
error(INVALID_PORTAL_NUMBER);
if (info[id].owner != 0 && info[id].owner != server_asid)
error(NOT_OWNER);
/* an ugly patch to allow the serial driver to redefine */
/* handlers */
if (portal_table[id] != bad_portal &&
(id < PORTAL_FD_START && id != SYS_SERIAL_FLUSH_QUEUE))
error(PORTAL_DEFINED);
break;
default:
error(INVALID_PORTAL_TEMPLATE);
}
switch(tolower(template[1])) {
case 'f':
stack_save = SAVE_FULL;
break;
case 'p':
stack_save = SAVE_PARTIAL;
break;
case 'm':
stack_save = SAVE_MINIMAL;
break;
default:
error(INVALID_PORTAL_TEMPLATE);
}
if (stack_type == STACK_EXCEPTION && stack_save != SAVE_FULL)
error(INVALID_PORTAL_COMBINATION);
s = &template[2];
if (strlen(s) < 1)
error(INVALID_PORTAL_TEMPLATE);
if (strlen(s) > MAX_PORTAL_ARGS)
error(TOO_MANY_PARAMETERS);
if (stack_type == STACK_QUEUE && strlen(s) > NREG_ARGS)
error(TOO_MANY_PARAMETERS);
asid_reg = const_reg = thread_reg = window_reg = bad_vaddr_reg = 0;
for (i = 0; s[i] != '\0'; i++) {
switch(tolower(s[i])) {
case '#':
/* can deliver the portal # only in first argument */
/* actually, we leave it there. */
if (i != 0)
error(INVALID_PORTAL_TEMPLATE);
break;
case 'a':
if (asid_reg != 0)
error(INVALID_PORTAL_TEMPLATE);
if (i >= NREG_ARGS)
error(INVALID_PORTAL_TEMPLATE);
asid_reg = A0+i;
break;
case 'c':
if (const_reg != 0)
error(INVALID_PORTAL_TEMPLATE);
check_synthetic_arg(id, i, s);
const_reg = A0+i;
break;
case 't':
if (thread_reg != 0)
error(INVALID_PORTAL_TEMPLATE);
check_synthetic_arg(id, i, s);
thread_reg = A0+i;
break;
case 'v':
if (bad_vaddr_reg != 0)
error(INVALID_PORTAL_TEMPLATE);
if (i >= NREG_ARGS)
error(INVALID_PORTAL_TEMPLATE);
bad_vaddr_reg = A0+i;
break;
case 'w':
case '>':
case '=':
if (window_reg != 0)
error(INVALID_PORTAL_TEMPLATE);
if (i >= NREG_ARGS)
error(INVALID_PORTAL_TEMPLATE);
window_reg = A0+i;
window_type = s[i];
break;
case 'i':
/* first parameter must be synthesized by portal code */
/* first user parameter is clubbered in any case! */
if (i == 0)
error(INVALID_PORTAL_TEMPLATE);
break;
default:
error(INVALID_PORTAL_TEMPLATE);
}
}
if (stack_type == STACK_QUEUE && stack_queue[server_asid] == NULL) {
stack_queue[server_asid] = domain_q_init(server_asid);
if (stack_queue[server_asid] == NULL ||
(int)stack_queue[server_asid] == -1)
error(MEMORY_ALLOCATION);
}
/*
* must flush the portal table entry to avoid overwriting the local copy
* in virtual memory.
*/
clean_cache(portals[install_asid].phys + id, sizeof(Portal));
/* note: return address is two instructions after entry point */
info[id].mem = gen_portal(save, entry,
(int *)((char *)get_domain_entry(server_asid) + 2*sizeof(int)),
stack_type, stack_save, stack_queue[server_asid],
thread_reg, const_reg, c, asid_reg, window_reg, window_type,
bad_vaddr_reg, &portal_len, &const_offset, &c_reg);
info[id].code = info[id].mem;
portal_table[id] = v2p(info[id].code);
info[id].template = strdup(template);
info[id].constant = c;
info[id].len = portal_len;
info[id].const_offset = const_offset;
info[id].c_reg = c_reg;
DIAG(PORTAL_DIAG, ("portal_table[%d]=%p\n", id, portal_table[id]));
/*
* must flush the cache for the portal table, since we access it through
* cached physical memory.
*/
clean_cache(portals[install_asid].virt + id, sizeof(Portal));
/* must flush again, since calling clean_cache caused caching of */
/* a portion of the portal table! */
clean_cache(portals[install_asid].phys + id, sizeof(Portal));
if (id < NPORTALS)
info[id].owner = server_asid;
if (portals[install_asid].notify_id > 0)
call_portal(portals[install_asid].notify_id, id, template);
DIAG(PORTAL_DIAG, ("new_portal generated portal %d in asid %d\n",
id, install_asid));
return id;
}
/*
* Create a new portal into the caller's domain using a parameters template
*/
int
sys_portal_create(int caller_asid, int id, char *template, uint c, int (*entry)(), uint install_2up)
{
int install_asid;
vlong save[S_REGS];
DIAG(PORTAL_DIAG,
("sys_portal_create: asid=%d id=%d template=%s c=%08x entry=%p install_2up=%d\n",
caller_asid, id, template, c, entry, install_2up));
if (install_2up) {
install_asid = get_caller_asid(2);
if (install_asid < 0)
error(GET_CALLER);
} else
install_asid = caller_asid;
if (get_caller(1, save) < 0)
error(GET_CALLER);
id = new_portal(install_asid, id, caller_asid, save, template, c, entry);
DIAG(PORTAL_DIAG,
("sys_portal_create generated portal %d in asid %d\n",
id, install_asid));
return id;
}
/*
* Create a new portal into the caller's child using a parameters template
*/
int
sys_portal_create_child(int parent_asid, int child_asid, int id,
char *template, uint c, int (*entry)())
{
vlong save[S_REGS];
DIAG(PORTAL_DIAG,
("sys_portal_create_child: parent_asid=%d child_asid=%d id=%d template=%s c=%d entry=%p\n",
parent_asid, child_asid, id, template, c, entry));
if (child_asid <= 0 || child_asid >= NASID)
error(INVALID_ASID);
if (portals[child_asid].parent_asid != parent_asid)
error(NOT_PARENT);
if (get_caller(1, save) < 0)
error(GET_CALLER);
id = new_portal(child_asid, id, parent_asid, save, template, c, entry);
DIAG(PORTAL_DIAG,
("sys_portal_create_child generated portal %d in asid %d\n",
id, child_asid));
return id;
}
/*
* Create a new portal into the caller's domain return the entry to the
* system calls table.
* This is a special portal, which DOES NOT add push its state on the
* activation stack.
* The first three parameters of the called routine are taken
* from parameters 2-4 of the portal.
* Note: there is NO specification string for this kind of portal!
* No parameter manipulations are performed!
*/
int
sys_portal_create0(int caller_asid, int id, int (*entry)())
{
vlong save[S_REGS];
Portal *portal_table;
Port_Info *info;
int portal_len;
char template[NAMELEN];
DIAG(PORTAL_DIAG,
("sys_portal_create0: caller_asid=%d id=%d entry=%p\n",
caller_asid, id, entry));
if (id <= 0 || id >= NPORTALS)
error(INVALID_PORTAL_NUMBER);
if (entry == NULL)
error(INVALID_ENTRY);
portal_table = portals[caller_asid].virt;
info = portals[caller_asid].info;
if (portal_table == NULL || info == NULL)
error(INTERNAL_ERROR_PORTALS);
if (info[id].owner != 0 && info[id].owner != caller_asid)
error(NOT_OWNER);
/* an ugly patch to allow the serial driver to redefine the handler */
if (portal_table[id] != bad_portal && id < PORTAL_FD_START)
error(PORTAL_DEFINED);
if (get_caller(1, save) < 0)
error(GET_CALLER);
/*
* must flush the portal table entry to avoid overwriting the local copy
* in virtual memory.
*/
clean_cache(portals[caller_asid].phys + id, sizeof(Portal));
/* note: return address is two instructions after entry point */
info[id].mem = gen_null_portal(save, entry, &portal_len);
info[id].code = info[id].mem;
portal_table[id] = v2p(info[id].code);
info[id].owner = caller_asid;
info[id].template = strdup("");
info[id].len = portal_len;
info[id].constant = 0;
info[id].const_offset = 0;
info[id].c_reg = ZERO;
/*
* must flush the cache for the portal table, since we access it through
* cached physical memory.
*/
clean_cache(portals[caller_asid].virt + id, sizeof(Portal));
/* must flush again, since calling clean_cache caused caching of */
/* a portion of the portal table! */
clean_cache(portals[caller_asid].phys + id, sizeof(Portal));
if (portals[caller_asid].notify_id > 0) {
strlcpy(template, "", NAMELEN);
call_portal(portals[caller_asid].notify_id, id, template);
}
DIAG(PORTAL_DIAG,
("sys_portal_create0 generated portal %d in asid %d\n",
id, caller_asid));
return id;
}
int
sys_portal_delete(int caller_asid, const int id, const int n,
const uint install_2up)
{
int asid, i;
Portal *portal_table;
Port_Info *info;
DIAG(PORTAL_DIAG,
("sys_portal_delete: caller_asid=%d id=%d n=%d install_2up=%d\n",
caller_asid, id, n, install_2up));
if (id < 0 || id >= NPORTALS || n < 1 || (id + n) > 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);
for (i = 0; i < n; i++)
if (info[id+i].owner != 0 &&
info[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[asid].phys + id, n*sizeof(Portal));
for (i = 0; i < n; i++) {
if (info[id+i].template != NULL)
free(info[id+i].template);
if (info[id+i].mem != NULL)
aligned_decref(info[id+i].mem);
portal_table[id+i] = bad_portal;
memset(&info[id+i], 0, sizeof(Port_Info));
}
/*
* must flush the cache for the portal table, since we access it through
* cached physical 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, n*sizeof(Portal));
return 0;
}
/*
* Find an existing portal group with the given name and replicate its
* portals. Return the first portal number of the newly replicated portals.
*
* Note: "name" may be not NUL terminated.
*/
int
sys_portal_open(int asid, const char *name, int n)
{
Elem *e;
int i, id;
Portal *portal_table;
Port_Info *info;
char template[NAMELEN];
DIAG(PORTAL_DIAG, ("sys_portal_open for asid=%d name=%s\n",
asid, name));
if (name == NULL || param_check(name, NAMELEN, 1) < 0 ||
name[0] == '\0')
error(INVALID_PORTAL_NAME);
if ((e = portal_lookup(name)) == NULL)
error(INVALID_PORTAL_NAME);
if (n != e->n)
error(INVALID_PORTAL_SET_SIZE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -