2009-05-20 23:07:56 +03:00
|
|
|
#pypp 0
|
|
|
|
#include "kernel.hh"
|
|
|
|
|
2009-05-25 01:31:35 +03:00
|
|
|
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->page == page:
|
|
|
|
return &page[num]
|
|
|
|
else:
|
|
|
|
// Normal capability
|
|
|
|
for Capability *c = capabilities; c; c = c->next:
|
|
|
|
if c == (Capability *)code:
|
|
|
|
return c
|
2009-05-20 23:07:56 +03:00
|
|
|
return NULL
|
|
|
|
|
2009-05-25 01:31:35 +03:00
|
|
|
static Capability *reply
|
|
|
|
|
|
|
|
static void reply_cap (unsigned target, unsigned protected_data):
|
|
|
|
Capability r
|
|
|
|
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)
|
|
|
|
unsigned d[4] = { 0, 0, 0, 0 }
|
|
|
|
Capability *caps[4] = { &r, NULL, NULL, NULL }
|
|
|
|
bool cops[4] = { true, false, false, false }
|
|
|
|
reply->invoke (d, caps, cops)
|
|
|
|
|
|
|
|
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 }
|
|
|
|
reply->invoke (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 }
|
|
|
|
reply->invoke (d, caps, cops)
|
|
|
|
|
|
|
|
static void admin_invoke (unsigned target, Capability *cap, unsigned request, unsigned data):
|
|
|
|
switch request:
|
|
|
|
case CAP_ADMIN_SCHEDULE:
|
|
|
|
schedule ()
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
|
|
|
|
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:
|
|
|
|
// TODO
|
|
|
|
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 request, unsigned data):
|
|
|
|
Thread *thread = (Thread *)protected_data
|
|
|
|
switch request:
|
|
|
|
case CAP_THREAD_RUN:
|
|
|
|
if data:
|
|
|
|
thread->run ()
|
|
|
|
else:
|
|
|
|
thread->unrun ()
|
|
|
|
break
|
|
|
|
case CAP_THREAD_GET_INFO:
|
|
|
|
// TODO
|
|
|
|
case CAP_THREAD_SET_INFO:
|
|
|
|
// TODO
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
|
|
|
|
static void page_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
|
|
|
|
Page *page
|
|
|
|
Cappage *cappage
|
|
|
|
if (target & CAPTYPE_MASK) == CAPTYPE_PAGE:
|
|
|
|
page = (Page *)protected_data
|
|
|
|
cappage = NULL
|
|
|
|
else:
|
|
|
|
page = NULL
|
|
|
|
cappage = (Cappage *)protected_data
|
|
|
|
switch request:
|
|
|
|
case CAP_PAGE_MAP:
|
|
|
|
if !page:
|
|
|
|
return
|
|
|
|
// TODO
|
|
|
|
case CAP_PAGE_SHARE:
|
|
|
|
// TODO
|
|
|
|
case CAP_PAGE_SHARE_COW:
|
|
|
|
// TODO
|
|
|
|
case CAP_PAGE_FORGET:
|
|
|
|
// TODO
|
|
|
|
case CAP_CAPPAGE_SET:
|
|
|
|
if !cappage:
|
|
|
|
return
|
|
|
|
// TODO
|
|
|
|
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]):
|
|
|
|
// 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 false
|
|
|
|
reply = c[0]
|
|
|
|
if d[0] == CAP_DEGRADE:
|
|
|
|
reply_cap (target & d[1], protected_data)
|
|
|
|
return true
|
|
|
|
switch target & CAPTYPE_MASK:
|
|
|
|
case CAPTYPE_ADMIN:
|
|
|
|
admin_invoke (target, c[1], d[0], d[1])
|
|
|
|
break
|
|
|
|
case CAPTYPE_RECEIVER:
|
|
|
|
if target & CAP_RECEIVER_CALL:
|
|
|
|
// This is a call capability.
|
|
|
|
// TODO
|
|
|
|
return false
|
|
|
|
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[0], d[1])
|
|
|
|
break
|
|
|
|
case CAPTYPE_PAGE:
|
|
|
|
page_invoke (target, protected_data, c[1], d[0], d[1])
|
|
|
|
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], d[0], d[1])
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
panic (0x99337744, "invalid capability type invoked")
|
|
|
|
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.
|
|
|
|
bool tried_direct = false
|
|
|
|
if target->owner && target->owner->is_waiting ():
|
|
|
|
Capability *c[4]
|
|
|
|
for unsigned i = 0; i < 4; ++i:
|
|
|
|
if !cap[i]:
|
|
|
|
c[i] = NULL
|
|
|
|
else:
|
|
|
|
c[i] = target->owner->address_space->clone_capability (cap[i], copy[i])
|
|
|
|
if !c[i]:
|
|
|
|
for unsigned j = 0; j < i; ++j:
|
|
|
|
target->owner->address_space->free_capability (c[i])
|
|
|
|
tried_direct = true
|
|
|
|
break
|
|
|
|
if !tried_direct:
|
|
|
|
Thread_arch_receive (target->owner, data, c)
|
|
|
|
target->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 = target->address_space->alloc_message (this)
|
|
|
|
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] = target->address_space->clone_capability (cap[i], copy[i])
|
|
|
|
if !msg->capabilities[i]:
|
|
|
|
for unsigned j = 0; j < i; ++j:
|
|
|
|
target->address_space->free_capability (msg->capabilities[j])
|
|
|
|
target->address_space->free_message (msg)
|
|
|
|
return false
|
|
|
|
if tried_direct:
|
|
|
|
Thread_arch_receive_fail (target->owner)
|
|
|
|
target->owner->unwait ()
|
|
|
|
return true
|
|
|
|
// This is a kernel capability. Use a function to allow optimized call capabilities.
|
|
|
|
return kernel_invoke ((unsigned)target, protected_data, data, cap, copy)
|