1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-02 19:42:57 +03:00
iris/invoke.ccp
Bas Wijnen e7f42c6b7e more
2009-05-28 23:35:27 +02:00

443 lines
14 KiB
COBOL

#pypp 0
#include "kernel.hh"
Capability *Memory::find_capability (unsigned code, bool *copy):
*copy = code & 2 ? true : false
if code & 1:
// Cappage capability
unsigned num = (code & ~PAGE_MASK) >> 1
if num >= CAPPAGE_SIZE:
return NULL
Capability *page = (Capability *)(code & PAGE_MASK)
for Cappage *p = cappages; p; p = p->next:
if p->data.frame == (unsigned)page:
return &page[num]
else:
// Normal capability
for Capability *c = capabilities; c; c = c->next:
if c == (Capability *)code:
return c
return NULL
static Capability *reply
static Receiver *reply_receiver
static void fill_cap (Capability *r, unsigned target, unsigned protected_data):
Capability **ref
if target & ~KERNEL_MASK:
ref = &((Receiver *)target)->capabilities
else:
ref = &((Object_base *)protected_data)->refs
// alloc_capability needs a Memory, but it isn't used if return storage is given.
top_memory.alloc_capability ((Receiver *)target, NULL, ref, protected_data, r)
static void reply_cap (unsigned target, unsigned protected_data):
Capability r
fill_cap (&r, target, protected_data)
unsigned d[4] = { 0, 0, 0, 0 }
Capability *caps[4] = { &r, NULL, NULL, NULL }
bool cops[4] = { true, false, false, false }
if reply:
reply->invoke (d, caps, cops)
else:
reply_receiver->send_message (~0, d, caps, cops)
r.invalidate ()
static void reply_cap (Capability *cap, bool copy):
unsigned d[4] = { 0, 0, 0, 0 }
Capability *caps[4] = { cap, NULL, NULL, NULL }
bool cops[4] = { copy, false, false, false }
if reply:
reply->invoke (d, caps, cops)
else:
reply_receiver->send_message (~0, d, caps, cops)
static void reply_num (unsigned num):
unsigned d[4] = { num, 0, 0, 0 }
Capability *caps[4] = { NULL, NULL, NULL, NULL }
bool cops[4] = { false, false, false, false }
if reply:
reply->invoke (d, caps, cops)
else:
reply_receiver->send_message (~0, d, caps, cops)
static void receiver_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Receiver *receiver = (Receiver *)protected_data
switch request:
case CAP_RECEIVER_SET_OWNER:
if ((unsigned)cap->target & (CAPTYPE_MASK | ~KERNEL_MASK)) != CAPTYPE_THREAD:
// FIXME: This makes it impossible to use a fake thread capability.
return
receiver->own ((Thread *)cap->protected_data)
break
case CAP_RECEIVER_CREATE_CAPABILITY:
reply_cap ((unsigned)receiver, data)
break
case CAP_RECEIVER_CREATE_CALL_CAPABILITY:
reply_cap (CAPTYPE_RECEIVER | CAP_RECEIVER_CALL, protected_data)
break
default:
break
static void memory_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Memory *mem = (Memory *)protected_data
switch request:
case CAP_MEMORY_CREATE:
switch data:
case CAPTYPE_RECEIVER:
Receiver *ret = mem->alloc_receiver ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_MEMORY:
Memory *ret = mem->alloc_memory ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_THREAD:
Thread *ret = mem->alloc_thread ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_PAGE:
Page *ret = mem->alloc_page ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_CAPPAGE:
Cappage *ret = mem->alloc_cappage ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
default:
return
break
case CAP_MEMORY_DESTROY:
if !cap || cap->address_space != mem || (unsigned)cap->target & ~KERNEL_MASK:
return
switch (unsigned)cap->target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER:
mem->free_receiver ((Receiver *)cap->protected_data)
return
case CAPTYPE_MEMORY:
mem->free_memory ((Memory *)cap->protected_data)
return
case CAPTYPE_THREAD:
mem->free_thread ((Thread *)cap->protected_data)
return
case CAPTYPE_PAGE:
mem->free_page ((Page *)cap->protected_data)
return
case CAPTYPE_CAPABILITY:
mem->free_capability ((Capability *)cap->protected_data)
return
case CAPTYPE_CAPPAGE:
mem->free_cappage ((Cappage *)cap->protected_data)
return
default:
panic (0x55228930, "invalid case")
break
case CAP_MEMORY_LIST:
// TODO
break
case CAP_MEMORY_MAPPING:
bool write
Page *page = mem->get_mapping (data, &write)
unsigned t = CAPTYPE_PAGE | REQUEST_MASK
if !write:
t &= ~CAP_PAGE_WRITE
reply_cap (t, (unsigned)page)
break
case CAP_MEMORY_SET_LIMIT:
mem->limit = data
break
case CAP_MEMORY_GET_LIMIT:
reply_num (mem->limit)
break
case CAP_MEMORY_DROP:
if cap->address_space != mem:
break
mem->free_capability (cap)
break
default:
break
static void thread_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned data[4]):
Thread *thread = (Thread *)protected_data
switch data[0]:
case CAP_THREAD_GET_INFO:
switch data[1]:
case CAP_THREAD_INFO_PC:
reply_num (thread->pc)
break
case CAP_THREAD_INFO_SP:
reply_num (thread->sp)
break
case CAP_THREAD_INFO_FLAGS:
reply_num (thread->flags)
break
default:
unsigned *n = Thread_arch_info (thread, data[1])
if n:
reply_num (*n)
break
break
case CAP_THREAD_SET_INFO:
unsigned *value
switch data[1]:
case CAP_THREAD_INFO_PC:
value = &thread->pc
break
case CAP_THREAD_INFO_SP:
value = &thread->sp
break
case CAP_THREAD_INFO_FLAGS:
// It is not possible to set the PRIV flag, but it can be reset.
data[2] &= ~THREAD_FLAG_PRIV
value = &thread->flags
if data[3] & ~THREAD_FLAG_USER:
unsigned v = (*value & data[3]) | (data[2] & data[3])
if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING):
if v & THREAD_FLAG_WAITING:
thread->wait ()
else
thread->unwait ()
if (v & THREAD_FLAG_RUNNING) != (*value & THREAD_FLAG_RUNNING):
if v & THREAD_FLAG_RUNNING:
thread->run ()
else
thread->unrun ()
break
default:
value = Thread_arch_info (thread, data[1])
break
if value:
*value &= ~data[3]
*value |= data[2] & data[3]
break
case CAP_THREAD_SCHEDULE:
schedule ()
break
case CAP_THREAD_REGISTER_INTERRUPT:
arch_register_interrupt (data[1], (Receiver *)cap->protected_data)
break
default:
break
static void page_invoke (unsigned target, unsigned protected_data, Capability *cap, bool copy, unsigned data[4]):
Page *page
Cappage *cappage
ShareData *share_data
if (target & CAPTYPE_MASK) == CAPTYPE_PAGE:
page = (Page *)protected_data
cappage = NULL
share_data = &page->data
else:
page = NULL
cappage = (Cappage *)protected_data
share_data = &cappage->data
switch data[0]:
case CAP_PAGE_MAP:
if !page:
return
page->address_space->map (page, data[1], target & CAP_PAGE_WRITE)
break
case CAP_PAGE_COPY:
// TODO
case CAP_PAGE_MOVE:
// TODO
case CAP_PAGE_GET_FLAGS:
reply_num (share_data->flags)
break
case CAP_PAGE_SET_FLAGS:
data[2] &= ~PAGE_FLAG_SHARED
if share_data->flags & PAGE_FLAG_SHARED:
data[1] &= ~(PAGE_FLAG_WRITABLE | PAGE_FLAG_NOSHARE)
unsigned old = share_data->flags
share_data->flags &= ~data[2]
share_data->flags |= data[1] & data[2]
if page && (share_data->flags ^ old) & PAGE_FLAG_WRITABLE:
Page_arch_update_mapping (page)
if (share_data->flags & ~old) & PAGE_FLAG_PAYING:
if page:
if !page->address_space->use():
break
else:
if !cappage->address_space->use():
break
else if (~share_data->flags & old) & PAGE_FLAG_PAYING:
// We stop paying. Free the frame if nobody else is paying.
if page:
Page *p
for p = (Page *)page->data.share_prev; p; p = (Page *)p->data.share_prev:
if p->data.flags & PAGE_FLAG_PAYING:
break
if !p:
for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next:
if p->data.flags & PAGE_FLAG_PAYING:
break
if p:
page->address_space->unuse()
else:
// No Page is paying for this frame anymore.
page->address_space->pfree (page->data.frame)
for p = page; p; p = (Page *)p->data.share_prev:
p->data.frame = NULL
for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next:
p->data.frame = NULL
else:
Cappage *p
for p = (Cappage *)cappage->data.share_prev; p; p = (Cappage *)p->data.share_prev:
if p->data.flags & PAGE_FLAG_PAYING:
break
if !p:
for p = (Cappage *)cappage->data.share_next; p; p = (Cappage *)p->data.share_next:
if p->data.flags & PAGE_FLAG_PAYING:
break
if p:
cappage->address_space->unuse()
else:
// No Page is paying for this frame anymore.
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
((Capability *)share_data->frame)[i].invalidate ()
cappage->address_space->pfree (cappage->data.frame)
for p = cappage; p; p = (Cappage *)p->data.share_prev:
p->data.frame = NULL
for p = (Cappage *)cappage->data.share_next; p; p = (Cappage *)p->data.share_next:
p->data.frame = NULL
break
case CAP_CAPPAGE_SET:
if !cappage || data[1] >= CAPPAGE_SIZE || !(target & CAP_PAGE_WRITE):
return
Capability *c = &((Capability *)cappage->data.frame)[data[1]]
c->invalidate ()
// clone_capability needs a Memory, but doesn't use it when storage is provided.
top_memory.clone_capability (cap, copy, c)
break
default:
break
static void capability_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Capability *capability = (Capability *)protected_data
switch request:
case CAP_CAPABILITY_GET:
reply_cap (capability, true)
break
case CAP_CAPABILITY_SET_DEATH_NOTIFY:
// TODO
default:
break
static bool kernel_invoke (unsigned target, unsigned protected_data, unsigned d[4], Capability *c[4], bool copy[4], Capability *self):
// Kernel calling convention:
// data[0] is the request.
// cap[0] is the reply capability
// other parameters' meanings depend on the operation.
if !((1 << d[0]) & target & ~REQUEST_MASK):
// You are not allowed to perform this operation.
return true
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_CALL))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)):
// This is a call capability.
Capability r
Capability *c0 = c[0]
if ~(unsigned)c0->target & ~KERNEL_MASK:
fill_cap (&r, protected_data, ~0)
c[0] = &r
copy[0] = true
bool ret = kernel_invoke ((unsigned)c0->target, c0->protected_data, d, c, copy, c0)
r.invalidate ()
return ret
else:
// Kernel call: don't create actual capablities.
reply = NULL
reply_receiver = (Receiver *)protected_data
return kernel_invoke ((unsigned)c0->target, c0->protected_data, d, c, copy, c0)
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
// This is a reply capability.
((Receiver *)protected_data)->send_message (~0, d, c, copy)
while self->parent:
self = self->parent
self->invalidate ()
return true
reply = c[0]
if d[0] == CAP_DEGRADE:
reply_cap (target & d[1], protected_data)
return true
switch target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER:
receiver_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_MEMORY:
memory_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_THREAD:
thread_invoke (target, protected_data, c[1], d)
break
case CAPTYPE_PAGE:
page_invoke (target, protected_data, c[1], copy[1], d)
break
case CAPTYPE_CAPABILITY:
capability_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_CAPPAGE:
page_invoke (target, protected_data, c[1], copy[1], d)
break
default:
panic (0x99337744, "invalid capability type invoked")
return true
bool Receiver::send_message (unsigned protected_data, unsigned data[4], Capability *cap[4], bool copy[4]):
bool tried_direct = false
if owner && owner->is_waiting ():
Capability *c[4]
for unsigned i = 0; i < 4; ++i:
if !cap[i]:
c[i] = NULL
else:
c[i] = owner->address_space->clone_capability (cap[i], copy[i])
if !c[i]:
for unsigned j = 0; j < i; ++j:
owner->address_space->free_capability (c[i])
tried_direct = true
break
if !tried_direct:
Thread_arch_receive (owner, data, c)
owner->unwait ()
return true
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
Message *msg = address_space->alloc_message (this, protected_data)
if !msg:
return false
for unsigned i = 0; i < 4; ++i:
msg->data[i] = data[i]
if !cap[i]:
msg->capabilities[i] = NULL
else:
msg->capabilities[i] = address_space->clone_capability (cap[i], copy[i])
if !msg->capabilities[i]:
for unsigned j = 0; j < i; ++j:
address_space->free_capability (msg->capabilities[j])
address_space->free_message (msg)
return false
if tried_direct:
Thread_arch_receive_fail (owner)
owner->unwait ()
return true
bool Capability::invoke (unsigned data[4], Capability *cap[4], bool copy[4]):
if (unsigned)target & ~KERNEL_MASK:
// This is not a kernel capability: send a message to the receiver.
return target->send_message (protected_data, data, cap, copy)
// This is a kernel capability. Use a function to allow optimized call capabilities.
return kernel_invoke ((unsigned)target, protected_data, data, cap, copy, this)