mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-05 08:37:30 +02:00
1073 lines
36 KiB
COBOL
1073 lines
36 KiB
COBOL
#pypp 0
|
|
// Iris: micro-kernel for a capability-based operating system.
|
|
// invoke.ccp: Capability invocation and kernel responses.
|
|
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "kernel.hh"
|
|
|
|
static void log_message (char const *prefix, unsigned target, unsigned pdata, kCapability::Context *c):
|
|
kdebug (prefix)
|
|
kdebug (": caller=")
|
|
if old_current:
|
|
kdebug_num (old_current->id, 2)
|
|
else
|
|
kdebug ("xx")
|
|
kdebug (":")
|
|
kdebug_num ((unsigned)old_current)
|
|
kdebug ("; target=")
|
|
kdebug_num (target)
|
|
kdebug ("; pdata=")
|
|
kdebug_num (pdata)
|
|
kdebug ("; data=")
|
|
kdebug_num (c->data[0].h)
|
|
kdebug (":")
|
|
kdebug_num (c->data[0].l)
|
|
kdebug (",")
|
|
kdebug_num (c->data[1].h)
|
|
kdebug (":")
|
|
kdebug_num (c->data[1].l)
|
|
if c->reply.valid ():
|
|
kdebug ("; reply target=")
|
|
kdebug_num ((unsigned)c->reply->target)
|
|
kdebug ("; pdata=")
|
|
kdebug_num (c->reply->protected_data.l)
|
|
if c->arg.valid ():
|
|
kdebug ("; arg target=")
|
|
kdebug_num ((unsigned)c->arg->target)
|
|
kdebug ("; pdata=")
|
|
kdebug_num (c->arg->protected_data.l)
|
|
kdebug ("\n")
|
|
|
|
void kThread::raise (unsigned code, unsigned data):
|
|
kdebug ("raise ")
|
|
if old_current:
|
|
kdebug_num (old_current->id, 2)
|
|
else:
|
|
kdebug ("xx")
|
|
kdebug (':')
|
|
kdebug_num ((unsigned)old_current)
|
|
kdebug ('/')
|
|
if code < Iris::NUM_EXCEPTION_CODES:
|
|
kdebug (Iris::exception_name[code])
|
|
else:
|
|
kdebug ("invalid code:")
|
|
kdebug_num (code)
|
|
kdebug ('/')
|
|
kdebug_num (data)
|
|
kdebug ('\n')
|
|
dpanic (code, "raise")
|
|
unrun ()
|
|
if slots < 1 || !slot[0].caps || !slot[0].caps->cap (0)->target:
|
|
return
|
|
kCapability::Context c
|
|
c.data[0] = Iris::Num (code, data)
|
|
slot[0].caps->cap (0)->invoke (&c)
|
|
|
|
// From user-provided, thus untrusted, data, find a capability.
|
|
kCapRef kThread::find_capability (unsigned code, bool *copy):
|
|
*copy = code & CAP_COPY
|
|
unsigned c = code & ~CAP_COPY
|
|
unsigned s = c >> 16
|
|
unsigned num = c & 0xffff
|
|
if s >= slots || !slot[s].caps || num >= slot[s].caps->size:
|
|
if c != CAP_NONE:
|
|
kdebug_num ((unsigned)old_current)
|
|
kdebug (": invalid capability ")
|
|
kdebug_num (code)
|
|
kdebug ('\n')
|
|
kdebug_num (num)
|
|
kdebug (':')
|
|
kdebug_num (s)
|
|
kdebug (" > ")
|
|
if slot[s].caps:
|
|
kdebug_num (slot[s].caps->size)
|
|
else:
|
|
kdebug ("no caps")
|
|
kdebug ('\n')
|
|
dpanic (code, "invalid capability")
|
|
return kCapRef ()
|
|
return kCapRef (slot[s].caps, num)
|
|
|
|
// Try to deliver a message.
|
|
bool kReceiver::try_deliver ():
|
|
if !messages:
|
|
return false
|
|
if !owner || !owner->is_waiting ():
|
|
return false
|
|
kMessage *m = last_message
|
|
if protected_only:
|
|
for ; m; m = (kMessage *)m->prev:
|
|
if m->protected_data.value () == reply_protected_data.value ():
|
|
protected_only = false
|
|
break
|
|
if !m:
|
|
return false
|
|
bool dummy
|
|
kCapRef c = owner->find_capability (owner->recv_reply, &dummy)
|
|
if c.valid ():
|
|
c.clone (kCapRef (&m->caps, 0), true)
|
|
c = owner->find_capability (owner->recv_arg, &dummy)
|
|
if c.valid ():
|
|
c.clone (kCapRef (&m->caps, 1), true)
|
|
kThread_arch_receive (owner, m->protected_data, m->data)
|
|
address_space->free_message (this, m)
|
|
owner->unwait ()
|
|
return true
|
|
|
|
// Send a message to a receiver; try to deliver it immediately.
|
|
bool kReceiver::send_message (Iris::Num protected_data, kCapability::Context *c):
|
|
//log_message ("send_message", (unsigned)this, protected_data.l, c)
|
|
if owner && owner->is_waiting () && (!protected_only || protected_data.value () == reply_protected_data.value ()):
|
|
if protected_only:
|
|
protected_only = false
|
|
bool dummy
|
|
kCapRef cap = owner->find_capability (owner->recv_reply, &dummy)
|
|
if cap.valid ():
|
|
cap.clone (c->reply, c->copy[0])
|
|
cap = owner->find_capability (owner->recv_arg, &dummy)
|
|
if cap.valid ():
|
|
cap.clone (c->arg, c->copy[1])
|
|
kThread_arch_receive (owner, protected_data, c->data)
|
|
owner->unwait ()
|
|
return true
|
|
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
|
|
kMessage *msg = NULL;
|
|
if queue_limit:
|
|
msg = address_space->alloc_message (this)
|
|
if msg:
|
|
--queue_limit
|
|
if !msg:
|
|
// TODO: use sender-provided storage.
|
|
if !msg:
|
|
return false
|
|
msg->protected_data = protected_data
|
|
for unsigned i = 0; i < 2; ++i:
|
|
msg->data[i] = c->data[i]
|
|
msg->caps.clone (0, c->reply, c->copy[0])
|
|
msg->caps.clone (1, c->arg, c->copy[1])
|
|
return true
|
|
|
|
static kCapability::Context *context
|
|
|
|
static void reply_num (Iris::Num num):
|
|
kCapability::Context c
|
|
c.data[0] = num
|
|
c.data[1] = 0
|
|
if reply_target:
|
|
reply_target->send_message (reply_protected, &c)
|
|
else
|
|
dpanic (0, "nothing to reply to")
|
|
|
|
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
|
|
kCapability::Context c
|
|
c.data[0] = Iris::Num (num1, num2)
|
|
c.data[1] = num3
|
|
if reply_target:
|
|
reply_target->send_message (reply_protected, &c)
|
|
else
|
|
dpanic (0, "nothing to reply to")
|
|
|
|
static void reply_cap (unsigned target, Iris::Num protected_data, kCapRef *ref, unsigned num = 0):
|
|
if !reply_target:
|
|
dpanic (0, "nothing to reply to")
|
|
return
|
|
replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref)
|
|
kCapability::Context c
|
|
c.arg = kCapRef (&replied_caps, 0)
|
|
c.copy[1] = true
|
|
c.data[0] = Iris::Num (num, 0)
|
|
reply_target->send_message (reply_protected, &c)
|
|
c.arg->invalidate ()
|
|
|
|
static void receiver_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
kReceiver *receiver = (kReceiver *)protected_data.l
|
|
switch cmd:
|
|
case Iris::Receiver::SET_OWNER & REQUEST_MASK:
|
|
if !c->arg.valid ():
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
unsigned cap = (unsigned)c->arg->target
|
|
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Iris::Thread::SET_OWNER):
|
|
// FIXME: This makes it impossible to use a fake kThread capability.
|
|
return
|
|
receiver->own ((kThread *)c->arg->protected_data.l)
|
|
break
|
|
case Iris::Receiver::CREATE_CAPABILITY & REQUEST_MASK:
|
|
reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities)
|
|
return
|
|
case Iris::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
|
|
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Iris::Receiver::CALL_ASYNC : Iris::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
|
|
return
|
|
case Iris::Receiver::GET_PROTECTED & REQUEST_MASK:
|
|
if !c->arg.valid () || c->arg->target != receiver:
|
|
if !c->arg.valid ():
|
|
kdebug ("invalid arg\n")
|
|
else:
|
|
kdebug ("target: ")
|
|
kdebug_num ((unsigned)c->arg->target)
|
|
kdebug ("/")
|
|
kdebug_num ((unsigned)c->arg->protected_data.h)
|
|
kdebug (":")
|
|
kdebug_num ((unsigned)c->arg->protected_data.l)
|
|
kdebug ("\n")
|
|
dpanic (0, "wrong argument for get_protected")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
reply_num (c->arg->protected_data)
|
|
return
|
|
case Iris::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK:
|
|
reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
|
|
return
|
|
case Iris::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
|
|
receiver->reply_protected_data = c->data[1]
|
|
// Adjust target protected data, so the reply will reach the caller.
|
|
if receiver == reply_target:
|
|
reply_protected = receiver->reply_protected_data
|
|
break
|
|
case Iris::Receiver::GET_ALARM & REQUEST_MASK:
|
|
reply_num (receiver->alarm_count)
|
|
return
|
|
case Iris::Receiver::SET_ALARM & REQUEST_MASK:
|
|
case Iris::Receiver::ADD_ALARM & REQUEST_MASK:
|
|
unsigned old = receiver->alarm_count
|
|
if cmd == (Iris::Receiver::SET_ALARM & REQUEST_MASK):
|
|
receiver->alarm_count = c->data[1].l
|
|
else:
|
|
receiver->alarm_count += c->data[1].l
|
|
if (old == ~0) ^ (receiver->alarm_count == ~0):
|
|
// The alarm stopped or started.
|
|
if old == ~0:
|
|
// It started.
|
|
receiver->prev_alarm = NULL
|
|
receiver->next_alarm = first_alarm
|
|
if receiver->next_alarm:
|
|
receiver->next_alarm->prev_alarm = receiver
|
|
first_alarm = receiver
|
|
else:
|
|
// It stopped.
|
|
if receiver->prev_alarm:
|
|
receiver->prev_alarm->next_alarm = receiver->next_alarm
|
|
else:
|
|
first_alarm = receiver->next_alarm
|
|
if receiver->next_alarm:
|
|
receiver->next_alarm->prev_alarm = receiver->prev_alarm
|
|
reply_num (receiver->alarm_count)
|
|
return
|
|
default:
|
|
dpanic (cmd, "invalid receiver operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
reply_num (0)
|
|
|
|
static void memory_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
kMemory *mem = (kMemory *)protected_data.l
|
|
switch cmd:
|
|
case Iris::Memory::CREATE & REQUEST_MASK:
|
|
switch c->data[0].h:
|
|
case CAPTYPE_RECEIVER:
|
|
kReceiver *ret = mem->alloc_receiver ()
|
|
if ret:
|
|
reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
|
|
else:
|
|
dpanic (0x03311992, "out of memory creating receiver")
|
|
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
|
return
|
|
case CAPTYPE_MEMORY:
|
|
kMemory *ret = mem->alloc_memory ()
|
|
if ret:
|
|
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
|
|
else:
|
|
dpanic (0x13311992, "out of memory creating memory")
|
|
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
|
return
|
|
case CAPTYPE_THREAD:
|
|
kThread *ret = mem->alloc_thread (c->data[1].l)
|
|
if ret:
|
|
reply_cap (CAPTYPE_THREAD | CAP_MASTER, (unsigned)ret, &ret->refs)
|
|
kdebug ("(created thread ")
|
|
kdebug_num ((unsigned)ret)
|
|
kdebug (")\n")
|
|
else:
|
|
dpanic (0x23311992, "out of memory creating thread")
|
|
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
|
return
|
|
case CAPTYPE_PAGE:
|
|
kPage *ret = mem->alloc_page ()
|
|
if ret:
|
|
reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
|
|
else:
|
|
dpanic (0x33311992, "out of memory creating page")
|
|
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
|
return
|
|
case CAPTYPE_CAPS:
|
|
kCaps *ret = mem->alloc_caps (c->data[1].l)
|
|
if ret:
|
|
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
|
|
else:
|
|
dpanic (0x43311992, "out of memory creating caps")
|
|
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
|
return
|
|
default:
|
|
dpanic (0, "invalid create type")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
break
|
|
case Iris::Memory::DESTROY & REQUEST_MASK:
|
|
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem:
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
// Send the reply before destroying things, because the target may be destroyed.
|
|
reply_num (0)
|
|
switch (unsigned)c->arg->target & CAPTYPE_MASK:
|
|
case CAPTYPE_RECEIVER:
|
|
mem->free_receiver ((kReceiver *)c->arg->protected_data.l)
|
|
break
|
|
case CAPTYPE_MEMORY:
|
|
mem->free_memory ((kMemory *)c->arg->protected_data.l)
|
|
break
|
|
case CAPTYPE_THREAD:
|
|
mem->free_thread ((kThread *)c->arg->protected_data.l)
|
|
break
|
|
case CAPTYPE_PAGE:
|
|
mem->free_page ((kPage *)c->arg->protected_data.l)
|
|
break
|
|
case CAPTYPE_CAPS:
|
|
mem->free_caps ((kCaps *)c->arg->protected_data.l)
|
|
break
|
|
default:
|
|
panic (0x55228930, "invalid case")
|
|
return
|
|
return
|
|
case Iris::Memory::LIST & REQUEST_MASK:
|
|
// TODO
|
|
break
|
|
case Iris::Memory::MAP & REQUEST_MASK:
|
|
// FIXME: this should work for fake pages as well.
|
|
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
|
|
dpanic (0x22993341, "Trying to map non-page")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
kPage *page = (kPage *)c->arg->protected_data.l
|
|
if page->address_space != mem:
|
|
dpanic (0x52993341, "Trying to map foreign page")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
if c->data[1].l & (unsigned)c->arg->target & Iris::Page::READONLY:
|
|
kdebug ("Mapping readonly because capability is readonly\n")
|
|
page->flags |= Iris::Page::MAPPED_READONLY
|
|
mem->map (page, c->data[1].l & PAGE_MASK)
|
|
break
|
|
case Iris::Memory::MAPPING & REQUEST_MASK:
|
|
kPage *page = mem->get_mapping (c->data[1].l)
|
|
if !page:
|
|
reply_num (Iris::ERR_UNMAPPED_READ)
|
|
return
|
|
unsigned t = CAPTYPE_PAGE | CAP_MASTER
|
|
if page->flags & Iris::Page::MAPPED_READONLY:
|
|
t |= Iris::Page::READONLY
|
|
reply_cap (t, (unsigned)page, &page->refs)
|
|
return
|
|
case Iris::Memory::GET_LIMIT & REQUEST_MASK:
|
|
reply_num (mem->limit)
|
|
return
|
|
case Iris::Memory::SET_LIMIT & REQUEST_MASK:
|
|
mem->limit = c->data[1].l
|
|
break
|
|
default:
|
|
dpanic (0, "invalid memory operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
reply_num (0)
|
|
|
|
static void thread_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
kThread *thread = (kThread *)protected_data.l
|
|
switch cmd:
|
|
case Iris::Thread::GET_INFO & REQUEST_MASK:
|
|
switch c->data[0].h:
|
|
case Iris::Thread::PC:
|
|
reply_num (thread->pc)
|
|
return
|
|
case Iris::Thread::SP:
|
|
reply_num (thread->sp)
|
|
return
|
|
case Iris::Thread::FLAGS:
|
|
reply_num (thread->flags)
|
|
return
|
|
default:
|
|
reply_num (*kThread_arch_info (thread, c->data[0].h))
|
|
return
|
|
case Iris::Thread::SET_INFO & REQUEST_MASK:
|
|
unsigned *value
|
|
switch c->data[0].h:
|
|
case Iris::Thread::PC:
|
|
value = &thread->pc
|
|
break
|
|
case Iris::Thread::SP:
|
|
value = &thread->sp
|
|
break
|
|
case Iris::Thread::FLAGS:
|
|
// It is not possible to set the PRIV flag (but it can be reset).
|
|
if c->data[1].l & Iris::Thread::PRIV:
|
|
c->data[1].h &= ~Iris::Thread::PRIV
|
|
value = &thread->flags
|
|
if c->data[1].h & ~Iris::Thread::USER_FLAGS:
|
|
unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
|
if (v & Iris::Thread::WAITING) != (*value & Iris::Thread::WAITING):
|
|
if v & Iris::Thread::WAITING:
|
|
thread->wait ()
|
|
else
|
|
thread->unwait ()
|
|
if (v & Iris::Thread::RUNNING) != (*value & Iris::Thread::RUNNING):
|
|
if v & Iris::Thread::RUNNING:
|
|
thread->run ()
|
|
else:
|
|
thread->unrun ()
|
|
break
|
|
default:
|
|
value = kThread_arch_info (thread, c->data[0].h)
|
|
break
|
|
if value:
|
|
*value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
|
break
|
|
case Iris::Thread::USE_SLOT & REQUEST_MASK:
|
|
if c->data[1].l >= thread->slots || !c->arg.valid ():
|
|
if c->data[1].l == 0xdeadbeef:
|
|
bool dummy
|
|
dbg_code.h = (unsigned)c->arg.deref ()
|
|
break
|
|
dbg_send (5, 3)
|
|
dpanic (c->data[1].l, "no argument given for USE_SLOT")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
// FIXME: This doesn't allow using a fake caps.
|
|
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Iris::Caps::USE):
|
|
dpanic ((unsigned)c->arg->target, "argument for USE_SLOT is not a caps")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
unsigned slot = c->data[1].l
|
|
kCaps *new_caps = (kCaps *)c->arg->protected_data.l
|
|
if slot >= thread->slots:
|
|
dpanic (0, "using invalid slot")
|
|
return
|
|
thread->unset_slot (slot)
|
|
thread->slot[slot].caps = new_caps
|
|
if new_caps:
|
|
thread->slot[slot].next = new_caps->first_slot
|
|
thread->slot[slot].caps = new_caps
|
|
new_caps->first_slot.thread = thread
|
|
new_caps->first_slot.index = slot
|
|
break
|
|
case Iris::Thread::GET_CAPS & REQUEST_MASK:
|
|
unsigned slot = c->data[1].l
|
|
if slot < thread->slots:
|
|
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->slot[slot].caps, &thread->slot[slot].caps->refs, thread->slots)
|
|
else:
|
|
reply_num (thread->slots)
|
|
return
|
|
case Iris::Thread::SCHEDULE & REQUEST_MASK:
|
|
do_schedule = true
|
|
return
|
|
default:
|
|
if !(thread->flags & Iris::Thread::PRIV):
|
|
dpanic (0, "invalid thread operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
switch cmd:
|
|
case Iris::Thread::PRIV_REGISTER_INTERRUPT & REQUEST_MASK:
|
|
arch_register_interrupt (c->data[1].l, c->arg.valid () && (((unsigned)c->arg->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->arg->protected_data.l : NULL)
|
|
break
|
|
case Iris::Thread::PRIV_GET_TOP_MEMORY & REQUEST_MASK:
|
|
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs)
|
|
return
|
|
case Iris::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
|
|
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
|
|
dpanic (0, "not a thread argument for make priv")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
((kThread *)c->arg->protected_data.l)->flags |= Iris::Thread::PRIV
|
|
break
|
|
case Iris::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
|
|
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
|
|
dpanic (0x54365435, "non-memory argument to alloc_range")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
kMemory *mem = (kMemory *)c->arg->protected_data.l
|
|
if !mem->use (c->data[1].l):
|
|
dpanic (0x34365435, "out of memory during alloc_range")
|
|
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
|
return
|
|
unsigned data = phys_alloc (c->data[1].l)
|
|
if !data:
|
|
mem->unuse (c->data[1].l)
|
|
dpanic (0x14365435, "out of memory during alloc_range")
|
|
reply_num (Iris::ERR_OUT_OF_MEMORY)
|
|
return
|
|
reply_num (data & ~0xc0000000)
|
|
return
|
|
case Iris::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
|
|
if !c->arg.valid ():
|
|
panic (0x71342134, "no argument provided for alloc physical")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
|
panic (0x21342134, "no page provided for alloc physical")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
kPage *page = (kPage *)c->arg->protected_data.l
|
|
page->forget ()
|
|
if !(c->data[1].l & 2):
|
|
if page->flags & Iris::Page::PAYING:
|
|
page->flags &= ~Iris::Page::PAYING
|
|
page->address_space->unuse ()
|
|
else:
|
|
// This is for mapping allocated ranges. They are already paid for. Record that.
|
|
if page->flags & Iris::Page::PAYING:
|
|
page->address_space->unuse ()
|
|
else:
|
|
page->flags |= Iris::Page::PAYING
|
|
page->frame = (c->data[1].l & PAGE_MASK) | 0x80000000
|
|
page->flags |= Iris::Page::FRAME
|
|
if !(c->data[1].l & 1):
|
|
page->flags |= Iris::Page::UNCACHED
|
|
if !(c->data[1].l & 2):
|
|
page->flags |= Iris::Page::PHYSICAL
|
|
kPage_arch_update_mapping (page)
|
|
break
|
|
case Iris::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
|
|
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
|
|
dpanic (0x99049380, "invalid page for physical address")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
kPage *page = (kPage *)c->arg->protected_data.l
|
|
reply_num (page->frame & ~0xc0000000)
|
|
return
|
|
case Iris::Thread::PRIV_REBOOT & REQUEST_MASK:
|
|
arch_reboot ()
|
|
case Iris::Thread::PRIV_POWEROFF & REQUEST_MASK:
|
|
arch_poweroff ()
|
|
case Iris::Thread::PRIV_BOOT & REQUEST_MASK:
|
|
arch_boot (c->data[1].l, c->data[1].h)
|
|
case Iris::Thread::PRIV_PANIC & REQUEST_MASK:
|
|
if c->data[1].l == 0xdeaddead:
|
|
dbg_code.l = 1
|
|
break
|
|
panic (c->data[1].l, "panic requested by thread")
|
|
reply_num (~0)
|
|
return
|
|
case Iris::Thread::DBG_SEND & REQUEST_MASK:
|
|
dbg_send (c->data[1].l, c->data[1].h)
|
|
break
|
|
default:
|
|
dpanic (0, "invalid priv thread operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
reply_num (0)
|
|
return
|
|
|
|
static void page_check_payment (kPage *page):
|
|
kPage *p
|
|
for p = page; p; p = p->share_prev:
|
|
if p->flags & Iris::Page::PAYING:
|
|
return
|
|
for p = page->share_next; p; p = p->share_next:
|
|
if p->flags & Iris::Page::PAYING:
|
|
return
|
|
// No kPage is paying for this frame anymore.
|
|
raw_pfree (page->frame)
|
|
kPage *next
|
|
for p = page->share_prev, next = (p ? p->share_prev : NULL); p; p = next, next = p->share_prev:
|
|
p->frame = NULL
|
|
p->share_prev = NULL
|
|
p->share_next = NULL
|
|
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
|
|
kPage_arch_update_mapping (p)
|
|
for p = page, next = p->share_next; p; p = next, next = p->share_next:
|
|
p->frame = NULL
|
|
p->share_prev = NULL
|
|
p->share_next = NULL
|
|
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
|
|
kPage_arch_update_mapping (p)
|
|
|
|
static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
kPage *page = (kPage *)protected_data.l
|
|
switch cmd & ~Iris::Page::READONLY:
|
|
case Iris::Page::SHARE & REQUEST_MASK:
|
|
if !c->arg.valid ():
|
|
// Cannot share without a target page.
|
|
dpanic (0, "no target page for share")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
|
|
// FIXME: This makes it impossible to use a fake kPage capability.
|
|
dpanic (0, "share target is no page")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
kPage *t = (kPage *)c->arg->protected_data.l
|
|
//kdebug ("sharing from ")
|
|
//kdebug_num ((unsigned)page)
|
|
//kdebug (" (frame ")
|
|
//kdebug_num (page->frame)
|
|
//kdebug (") to ")
|
|
//kdebug_num ((unsigned)t)
|
|
//kdebug (" (frame ")
|
|
//kdebug_num (t->frame)
|
|
//kdebug (")\n")
|
|
if t != page:
|
|
t->forget ()
|
|
if c->data[0].h & Iris::Page::READONLY || cmd & Iris::Page::READONLY:
|
|
t->flags |= Iris::Page::READONLY
|
|
if !(page->flags & Iris::Page::FRAME):
|
|
kdebug ("share problem: ")
|
|
kdebug_num (page->flags)
|
|
kdebug ("\n")
|
|
dpanic (0, "sharing nothing results in lost page")
|
|
kPage_arch_update_mapping (t)
|
|
break
|
|
if c->data[0].h & Iris::Page::COPY:
|
|
if ~t->flags & Iris::Page::PAYING:
|
|
kPage_arch_update_mapping (t)
|
|
break
|
|
if !(c->data[0].h & Iris::Page::FORGET) || page->flags & Iris::Page::SHARED:
|
|
unsigned *d = (unsigned *)page->frame
|
|
if t == page:
|
|
kPage *other = page->share_next ? page->share_next : page->share_prev
|
|
if !other:
|
|
kPage_arch_update_mapping (t)
|
|
break
|
|
if page->share_next:
|
|
page->share_next->share_prev = page->share_prev
|
|
if page->share_prev:
|
|
page->share_prev->share_next = page->share_next
|
|
page->share_next = NULL
|
|
page->share_prev = NULL
|
|
page_check_payment (other)
|
|
else:
|
|
t->flags |= Iris::Page::FRAME
|
|
t->frame = raw_zalloc ()
|
|
for unsigned i = 0; i < PAGE_SIZE; i += 4:
|
|
((unsigned *)t->frame)[i >> 2] = d[i >> 2]
|
|
if c->data[0].h & Iris::Page::FORGET:
|
|
page->frame = NULL
|
|
page->flags &= ~Iris::Page::FRAME
|
|
kPage_arch_update_mapping (page)
|
|
else:
|
|
if t != page:
|
|
t->frame = page->frame
|
|
t->flags |= Iris::Page::FRAME
|
|
page->frame = NULL
|
|
page->flags &= ~Iris::Page::FRAME
|
|
kPage_arch_update_mapping (page)
|
|
else:
|
|
dpanic (0, "sharing page with itself...")
|
|
else:
|
|
if t == page:
|
|
dpanic (0, "sharing page with itself")
|
|
kPage_arch_update_mapping (t)
|
|
break
|
|
if c->data[0].h & Iris::Page::FORGET:
|
|
if ~page->flags & Iris::Page::SHARED:
|
|
if t->flags & Iris::Page::PAYING:
|
|
t->frame = page->frame
|
|
t->flags |= Iris::Page::FRAME
|
|
else:
|
|
dpanic (0, "move page failed because target is not paying")
|
|
page->frame = NULL
|
|
page->flags &= ~Iris::Page::FRAME
|
|
kPage_arch_update_mapping (page)
|
|
else:
|
|
t->share_prev = page->share_prev
|
|
t->share_next = page->share_next
|
|
if t->share_prev:
|
|
t->share_prev->share_next = t
|
|
if t->share_next:
|
|
t->share_next->share_prev = t
|
|
page->share_prev = NULL
|
|
page->share_next = NULL
|
|
page->forget ()
|
|
page_check_payment (t)
|
|
else:
|
|
t->share_prev = page->share_prev
|
|
t->share_next = page
|
|
page->share_prev = t
|
|
if t->share_prev:
|
|
t->share_prev->share_next = t
|
|
t->frame = page->frame
|
|
t->flags |= Iris::Page::FRAME
|
|
kPage_arch_update_mapping (t)
|
|
break
|
|
case Iris::Page::GET_FLAGS & REQUEST_MASK:
|
|
reply_num (page->flags)
|
|
return
|
|
case Iris::Page::SET_FLAGS & REQUEST_MASK:
|
|
if cmd & Iris::Page::READONLY:
|
|
dpanic (0, "setting page flags denied")
|
|
reply_num (Iris::ERR_WRITE_DENIED)
|
|
return
|
|
// Always refuse to set reserved flags.
|
|
c->data[1].h &= ~(Iris::Page::PHYSICAL | Iris::Page::UNCACHED)
|
|
// Remember the old flags.
|
|
unsigned old = page->flags
|
|
// Compute the new flags.
|
|
page->flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
|
|
|
|
// If we stop paying, see if the frame is still paid for. If not, free it.
|
|
if ~page->flags & old & Iris::Page::PAYING:
|
|
// Decrease the use counter in any case.
|
|
page->address_space->unuse ()
|
|
page_check_payment (page)
|
|
|
|
// If we start paying, increase the use counter.
|
|
if page->flags & ~old & Iris::Page::PAYING:
|
|
if !page->address_space->use():
|
|
dpanic (0, "cannot pay for frame")
|
|
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
|
|
page->flags &= ~(Iris::Page::PAYING | Iris::Page::FRAME)
|
|
// However, if there already was a frame, keep it.
|
|
if old & Iris::Page::FRAME:
|
|
page->flags |= Iris::Page::FRAME
|
|
|
|
// If we want a frame, see if we can get it.
|
|
if ~old & page->flags & Iris::Page::FRAME:
|
|
if ~page->flags & Iris::Page::PAYING:
|
|
dpanic (0, "cannot have frame without paying")
|
|
page->flags &= ~Iris::Page::FRAME
|
|
else:
|
|
page->frame = page->address_space->zalloc ()
|
|
kPage_arch_update_mapping (page)
|
|
break
|
|
default:
|
|
dpanic (0, "invalid page operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
if page->flags > 0x7f:
|
|
dpanic (page->flags, "weird output from page operation")
|
|
reply_num (0)
|
|
|
|
static void print_cap (kCapRef cap, kCapRef self):
|
|
if cap.deref () == self.deref ():
|
|
kdebug ('{')
|
|
else:
|
|
kdebug ('[')
|
|
kdebug_num ((unsigned)cap.caps)
|
|
kdebug (':')
|
|
kdebug_num (cap.index, 1)
|
|
if !cap.valid ():
|
|
kdebug ('!')
|
|
else:
|
|
kdebug ('=')
|
|
kdebug_num ((unsigned)cap->target)
|
|
kdebug (':')
|
|
kdebug_num (cap->protected_data.l)
|
|
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
|
|
print_cap (c, self)
|
|
if cap.deref () == self.deref ():
|
|
kdebug ('}')
|
|
else:
|
|
kdebug (']')
|
|
|
|
static void caps_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
kCaps *caps = (kCapsP)protected_data.l
|
|
switch cmd:
|
|
case Iris::Caps::GET & REQUEST_MASK:
|
|
if c->data[1].l >= caps->size:
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
kdebug_num ((unsigned)caps)
|
|
kdebug (" size: ")
|
|
kdebug_num (caps->size)
|
|
kdebug ('\n')
|
|
dpanic (c->data[1].l, "invalid index for get caps")
|
|
return
|
|
kCapability *ret = caps->cap (c->data[1].l)
|
|
#if 0
|
|
kdebug_num ((unsigned)caps)
|
|
kdebug (" get cap ")
|
|
kdebug_num (c->data[1].l)
|
|
kdebug (" = ")
|
|
kdebug_num ((unsigned)ret->target)
|
|
kdebug ("/")
|
|
kdebug_num (ret->protected_data.h)
|
|
kdebug (":")
|
|
kdebug_num (ret->protected_data.l)
|
|
kdebug ("\n")
|
|
#endif
|
|
reply_cap ((unsigned)ret->target, ret->protected_data, ((unsigned)ret->target & ~KERNEL_MASK) == 0 ? &((kObject *)ret->protected_data.l)->refs : &ret->target->capabilities)
|
|
return
|
|
case Iris::Caps::GET_SIZE & REQUEST_MASK:
|
|
reply_num (caps->size)
|
|
return
|
|
case Iris::Caps::SET & REQUEST_MASK:
|
|
if c->data[1].l >= caps->size:
|
|
dpanic (0, "invalid index for set caps")
|
|
return
|
|
caps->clone (c->data[1].l, c->arg, c->copy[1])
|
|
reply_num (0)
|
|
//kdebug_num ((unsigned)caps)
|
|
//kdebug (" set cap ")
|
|
//kdebug_num (c->data[1].l)
|
|
//kdebug (" to ")
|
|
//kdebug_num ((unsigned)caps->caps[c->data[1].l].target)
|
|
//kdebug ("/")
|
|
//kdebug_num (caps->caps[c->data[1].l].protected_data.h)
|
|
//kdebug (":")
|
|
//kdebug_num (caps->caps[c->data[1].l].protected_data.l)
|
|
//kdebug ("\n")
|
|
return
|
|
case Iris::Caps::TRUNCATE & REQUEST_MASK:
|
|
dpanic (0, "truncate caps is not implemented yet.")
|
|
return
|
|
case Iris::Caps::PRINT & REQUEST_MASK:
|
|
if c->data[1].l >= caps->size:
|
|
dpanic (0, "invalid caps for print")
|
|
return
|
|
kCapRef cap (caps, c->data[1].l)
|
|
kCapRef orig (caps, c->data[1].l)
|
|
while cap->parent.valid ():
|
|
while cap->sibling_prev.valid ():
|
|
if cap->parent.deref () != cap->sibling_prev->parent.deref ():
|
|
dpanic (0, "parent problem in cap data")
|
|
return
|
|
if cap.deref () != cap->sibling_prev->sibling_next.deref ():
|
|
dpanic (0, "prev error in cap data")
|
|
return
|
|
cap = cap->sibling_prev
|
|
if cap->parent->children.deref () != cap.deref ():
|
|
dpanic (0, "parent error in cap data")
|
|
return
|
|
cap = cap->parent
|
|
while cap->sibling_prev.valid ():
|
|
if cap->parent.deref () != cap->sibling_prev->parent.deref ():
|
|
dpanic (0, "parent parent problem in cap data")
|
|
return
|
|
if cap.deref () != cap->sibling_prev->sibling_next.deref ():
|
|
dpanic (0, "parent prev error in cap data")
|
|
return
|
|
cap = cap->sibling_prev
|
|
while cap.valid ():
|
|
print_cap (cap, orig)
|
|
cap = cap->sibling_next
|
|
kdebug ('\n')
|
|
return
|
|
default:
|
|
dpanic (cmd, "invalid caps operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
|
|
static void list_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
kList *list = (kListP)protected_data.l
|
|
if cmd == Iris::List::SET_CB & REQUEST_MASK:
|
|
list->owner.clone (0, c->arg, c->copy[1])
|
|
return
|
|
kListitem *item
|
|
if !c->arg.valid ():
|
|
item = NULL
|
|
else:
|
|
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM:
|
|
dpanic (0, "invalid request for list: arg is no listitem")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
item = (kListitem *)c->arg->protected_data.l
|
|
if item->list != list:
|
|
dpanic (0, "item list is not equal to called object")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
switch cmd:
|
|
case Iris::List::GET_NEXT & REQUEST_MASK:
|
|
if !item:
|
|
item = list->first_listitem
|
|
else:
|
|
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Iris::Listitem::LIST:
|
|
dpanic (0, "trying to get next listitem with insufficient rights")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
item = item->next_item
|
|
if !item:
|
|
reply_num (0)
|
|
return
|
|
reply_cap (CAPTYPE_LISTITEM | Iris::Listitem::LIST, (unsigned)item, &item->refs)
|
|
return
|
|
case Iris::List::ADD_ITEM & REQUEST_MASK:
|
|
if !item:
|
|
dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Iris::Listitem::ADD:
|
|
dpanic (0, "trying to add listitem with insufficient rights")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
((kListitem *)c->arg->protected_data.l)->add (list)
|
|
break
|
|
case Iris::List::GET_INFO & REQUEST_MASK:
|
|
if !item:
|
|
dpanic (0, "no item for List::GET_INFO")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT, ~0, ~0)
|
|
return
|
|
reply_num (item->info)
|
|
return
|
|
case Iris::List::SET_INFO & REQUEST_MASK:
|
|
if !item:
|
|
dpanic (0, "no item for List::SET_INFO")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
item->info = c->data[1]
|
|
break
|
|
case Iris::List::GET_CAP & REQUEST_MASK:
|
|
if !item:
|
|
dpanic (0, "no item for List::GET_CAP")
|
|
reply_num (Iris::ERR_INVALID_ARGUMENT)
|
|
return
|
|
kCapability *cap = item->target.cap (0)
|
|
reply_cap ((unsigned)cap->target, cap->protected_data, ((unsigned)cap->target & ~KERNEL_MASK) == 0 ? &((kObject *)cap->target)->refs : &cap->target->capabilities)
|
|
return
|
|
default:
|
|
dpanic (0, "invalid list operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
reply_num (0)
|
|
|
|
static void listitem_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
kListitem *item = (kListitemP)protected_data.l
|
|
switch cmd:
|
|
case Iris::Listitem::CLEAR & REQUEST_MASK:
|
|
// Disable linked capability.
|
|
item->add (NULL)
|
|
break
|
|
case Iris::Listitem::SET_CAP & REQUEST_MASK:
|
|
// Set linked capability.
|
|
item->target.clone (0, c->arg, c->copy[1])
|
|
break
|
|
default:
|
|
dpanic (0, "invalid listitem operation")
|
|
reply_num (Iris::ERR_INVALID_OPERATION)
|
|
return
|
|
reply_num (0)
|
|
|
|
static void kill_reply (kReceiver *r):
|
|
kCapRef cap = r->refs
|
|
while cap.valid ():
|
|
kCapability *c = cap.deref ()
|
|
cap = c->sibling_next
|
|
if (unsigned)c->target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
|
|
c->invalidate ()
|
|
|
|
static void kernel_invoke (unsigned target, Iris::Num protected_data, kCapability::Context *c):
|
|
// Kernel calling convention:
|
|
// data[0].l is the request.
|
|
// reply is the reply capability, or (for call capabilities) the target to call.
|
|
// other parameters' meanings depend on the operation.
|
|
if target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL_ASYNC):
|
|
// This is a call capability. reply is the capability to call.
|
|
kReceiver *owner = (kReceiver *)protected_data.l
|
|
owner->protected_only = target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL)
|
|
if must_wait:
|
|
old_current->wait ()
|
|
if !reply_target:
|
|
if (c->reply.index & ~CAP_COPY) != CAP_NONE:
|
|
kdebug ("target index: ")
|
|
kdebug_num (c->reply.index)
|
|
kdebug ("\n")
|
|
dpanic (0x54635675, "no target to call")
|
|
return
|
|
if ((unsigned)reply_target & ~KERNEL_MASK) != 0:
|
|
// This is a user-implemented object. Create a real reply capability.
|
|
kReceiver *call_target = reply_target
|
|
c->reply = kCapRef (&reply_caps, 0)
|
|
c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Iris::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs)
|
|
c->copy[0] = true
|
|
call_target->send_message (reply_protected, c)
|
|
c->reply->invalidate ()
|
|
else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
|
|
// Reply capability: destroy all before invoke.
|
|
kReceiver *r = (kReceiver *)reply_protected.l
|
|
kill_reply (r)
|
|
r->send_message (r->reply_protected_data, c)
|
|
else:
|
|
// Kernel call: don't create actual capablities.
|
|
kCapRef call_target = c->reply
|
|
c->reply.reset ()
|
|
reply_target = (kReceiver *)protected_data.l
|
|
reply_protected = reply_target->reply_protected_data
|
|
kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c)
|
|
return
|
|
if must_wait:
|
|
old_current->wait ()
|
|
if target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
|
|
// This is a reply capability.
|
|
kReceiver *r = (kReceiver *)protected_data.l
|
|
kill_reply (r)
|
|
r->send_message (r->reply_protected_data, c)
|
|
return
|
|
if !target:
|
|
return
|
|
unsigned cmd
|
|
if (target & REQUEST_MASK) == CAP_MASTER:
|
|
if c->data[0].l & CAP_MASTER_CREATE:
|
|
reply_cap (target | (c->data[0].l & REQUEST_MASK), protected_data, &((kObject *)protected_data.l)->refs)
|
|
return
|
|
cmd = c->data[0].l
|
|
c->data[0].l = 0
|
|
else:
|
|
cmd = target
|
|
cmd &= REQUEST_MASK
|
|
switch target & CAPTYPE_MASK:
|
|
case CAPTYPE_RECEIVER:
|
|
receiver_invoke (cmd, target, protected_data, c)
|
|
break
|
|
case CAPTYPE_MEMORY:
|
|
memory_invoke (cmd, target, protected_data, c)
|
|
break
|
|
case CAPTYPE_THREAD:
|
|
thread_invoke (cmd, target, protected_data, c)
|
|
break
|
|
case CAPTYPE_PAGE:
|
|
page_invoke (cmd, target, protected_data, c)
|
|
break
|
|
case CAPTYPE_CAPS:
|
|
caps_invoke (cmd, target, protected_data, c)
|
|
break
|
|
case CAPTYPE_LIST:
|
|
list_invoke (cmd, target, protected_data, c)
|
|
break
|
|
case CAPTYPE_LISTITEM:
|
|
listitem_invoke (cmd, target, protected_data, c)
|
|
break
|
|
default:
|
|
panic (0x99337744, "invalid capability type invoked")
|
|
return
|
|
return
|
|
|
|
void invoke (kReceiverP target, Iris::Num protected_data, kCapability::Context *c):
|
|
if dbg_code.l && old_current->id != 1:
|
|
log_message ("invoke", (unsigned)target, protected_data.l, c)
|
|
if (unsigned)target & ~KERNEL_MASK:
|
|
// This is not a kernel capability: send a message to the receiver.
|
|
if must_wait:
|
|
old_current->wait ()
|
|
//else
|
|
// log_message ("user invoke", (unsigned)target, protected_data.l, c)
|
|
target->send_message (protected_data, c)
|
|
return
|
|
// This is a kernel capability. Use a function to allow optimized call capabilities.
|
|
//if !must_wait && old_current->id == ~0
|
|
// log_message ("kernel invoke", (unsigned)target, protected_data.l, c)
|
|
context = c
|
|
if c->reply.valid ():
|
|
reply_target = c->reply->target
|
|
reply_protected = c->reply->protected_data
|
|
else:
|
|
reply_target = NULL
|
|
reply_protected.l = 0
|
|
kernel_invoke ((unsigned)target, protected_data, c)
|