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