1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-05 04:06:14 +02:00
iris/invoke.ccp

852 lines
29 KiB
Plaintext
Raw Normal View History

2009-05-20 23:07:56 +03:00
#pypp 0
2009-06-01 15:26:42 +03:00
// 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/>.
2009-05-20 23:07:56 +03:00
#include "kernel.hh"
2009-09-06 12:04:09 +03:00
static void log_message (char const *prefix, unsigned target, unsigned pdata, kCapability::Context *c):
if !dbg_code.l:
dbg_log (prefix)
dbg_log (": ")
dbg_log_num ((unsigned)old_current)
dbg_log (" > ")
dbg_log_num (target)
dbg_log (":")
dbg_log_num (pdata)
dbg_log ("/")
dbg_log_num (c->data[0].l)
dbg_log (" ")
dbg_log_num (c->data[0].h)
dbg_log (",")
dbg_log_num (c->data[1].l)
dbg_log (" ")
dbg_log_num (c->data[1].h)
dbg_log (",")
dbg_log_num (pdata)
dbg_log (";")
if c->reply.valid ():
dbg_log_num ((unsigned)c->reply->target)
dbg_log (":")
dbg_log_num (c->reply->protected_data.l)
dbg_log (",")
if c->arg.valid ():
dbg_log_num ((unsigned)c->arg->target)
dbg_log (":")
dbg_log_num (c->arg->protected_data.l)
dbg_log ("\n")
void kThread::raise (unsigned code, unsigned data):
2009-08-24 22:02:35 +03:00
dpanic (code, "raise")
2009-07-25 01:54:12 +03:00
dbg_log ("raise ")
dbg_log_num ((unsigned)current)
dbg_log_char ('/')
2009-09-06 12:04:09 +03:00
if code < Kernel::NUM_EXCEPTION_CODES:
dbg_log (Kernel::exception_name[code])
2009-07-25 01:54:12 +03:00
else:
dbg_log ("invalid code:")
dbg_log_num (code)
dbg_log_char ('/')
dbg_log_num (data)
dbg_log_char ('\n')
unrun ()
if slots < 1 || !caps[0] || !caps[0]->cap (0)->target:
2009-07-25 01:54:12 +03:00
return
kCapability::Context c
2009-09-06 12:04:09 +03:00
c.data[0] = Kernel::Num (code, data)
caps[0]->cap (0)->invoke (&c)
2009-07-25 01:54:12 +03:00
2009-07-05 11:52:44 +03:00
// 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 slot = c >> 16
unsigned num = c & 0xffff
if slot >= slots || !caps[slot] || num >= caps[slot]->size:
if c != CAP_NONE:
2009-08-24 22:02:35 +03:00
dpanic (code, "debug")
2009-07-25 01:54:12 +03:00
dbg_log_num ((unsigned)old_current)
dbg_log (": invalid capability ")
dbg_log_num (code)
2009-07-25 01:54:12 +03:00
dbg_log_char ('\n')
2009-08-24 22:02:35 +03:00
dbg_log_num (num)
dbg_log_char (':')
dbg_log_num (slot)
dbg_log (" > ")
if caps[slot]:
dbg_log_num (caps[slot]->size)
else:
dbg_log ("no caps")
dbg_log_char ('\n')
return kCapRef ()
return kCapRef (caps[slot], num)
2009-07-05 11:52:44 +03:00
// Try to deliver a message.
bool kReceiver::try_deliver ():
2009-07-20 01:23:45 +03:00
if !messages:
2009-06-01 02:12:54 +03:00
return false
2009-07-20 01:23:45 +03:00
if !owner || !owner->is_waiting ():
return false
kMessage *m = last_message
2009-06-01 02:12:54 +03:00
if protected_only:
for ; m; m = (kMessage *)m->prev:
2009-09-06 12:04:09 +03:00
if m->protected_data.value () == reply_protected_data.value ():
2009-07-20 01:23:45 +03:00
protected_only = false
2009-06-01 02:12:54 +03:00
break
2009-07-23 13:06:32 +03:00
if !m:
return false
2009-09-06 12:04:09 +03:00
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)
2009-07-20 01:23:45 +03:00
address_space->free_message (this, m)
2009-06-01 02:12:54 +03:00
owner->unwait ()
return true
2009-07-05 11:52:44 +03:00
// Send a message to a receiver; try to deliver it immediately.
2009-09-06 12:04:09 +03:00
bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *c):
//log_message ("send_message", (unsigned)this, protected_data.l, c)
if owner && owner->is_waiting () && (protected_data.value () == reply_protected_data.value () || !protected_only):
if protected_only:
2009-07-25 01:54:12 +03:00
protected_only = false
2009-09-06 12:04:09 +03:00
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)
2009-07-25 01:54:12 +03:00
owner->unwait ()
return true
2009-06-01 02:12:54 +03:00
// 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.
2009-06-01 02:12:54 +03:00
if !msg:
return false
2009-09-06 12:04:09 +03:00
msg->protected_data = protected_data
if protected_only && protected_data.value () == reply_protected_data.value ():
2009-07-20 01:23:45 +03:00
// Put this message in the end (where it will be first seen). Clear the protected_only flag.
protected_only = false
if msg->next:
((kMessage *)msg->next)->prev = NULL
messages = (kMessage *)msg->next
2009-07-20 01:23:45 +03:00
msg->next = NULL
msg->prev = last_message
((kMessage *)msg->prev)->next = msg
2009-07-20 01:23:45 +03:00
last_message = msg
for unsigned i = 0; i < 2; ++i:
2009-06-10 23:54:12 +03:00
msg->data[i] = c->data[i]
2009-09-06 12:04:09 +03:00
msg->caps.clone (0, c->reply, c->copy[0])
msg->caps.clone (1, c->arg, c->copy[1])
2009-06-01 02:12:54 +03:00
return true
2009-09-06 12:04:09 +03:00
static kCapability::Context *context
// reply_caps is the source of a receiver-generated reply capability.
// replied_caps is the source of kernel-generated capabilities which are used as arguments in a reply.
static kCaps reply_caps, replied_caps
static kReceiver *reply_target
2009-09-06 12:04:09 +03:00
static Kernel::Num reply_protected
2009-05-27 19:33:05 +03:00
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
kCapability::Context c
2009-09-06 12:04:09 +03:00
c.data[0] = Kernel::Num (num1, num2)
c.data[1] = num3
2009-09-06 12:04:09 +03:00
if reply_target:
reply_target->send_message (reply_protected, &c)
else:
dpanic (0, "nothing to reply to")
2009-06-01 02:12:54 +03:00
2009-09-07 00:34:50 +03:00
static void reply_cap (unsigned target, Kernel::Num protected_data, kCapRef *ref, unsigned num = 0):
2009-09-06 12:04:09 +03:00
replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref)
kCapability::Context c
c.arg = kCapRef (&replied_caps, 0)
c.copy[1] = true
2009-09-07 00:34:50 +03:00
c.data[0] = Kernel::Num (num, 0)
2009-09-06 12:04:09 +03:00
if reply_target:
reply_target->send_message (reply_protected, &c)
2009-08-24 22:02:35 +03:00
else:
2009-09-06 12:04:09 +03:00
dpanic (0, "nothing to reply to")
c.arg->invalidate ()
2009-05-25 01:31:35 +03:00
2009-09-06 12:04:09 +03:00
static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kReceiver *receiver = (kReceiver *)protected_data.l
switch cmd:
2009-09-07 00:34:50 +03:00
case Kernel::Receiver::SET_OWNER & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if !c->arg.valid ():
reply_num (~0)
2009-05-25 01:31:35 +03:00
return
2009-09-06 12:04:09 +03:00
unsigned cap = (unsigned)c->arg->target
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER):
// FIXME: This makes it impossible to use a fake kThread capability.
return
2009-09-06 12:04:09 +03:00
receiver->own ((kThread *)c->arg->protected_data.l)
2009-06-01 02:12:54 +03:00
break
2009-09-07 00:34:50 +03:00
case Kernel::Receiver::CREATE_CAPABILITY & REQUEST_MASK:
reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities)
return
2009-09-07 00:34:50 +03:00
case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
return
2009-09-07 00:34:50 +03:00
case Kernel::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
2009-09-07 00:34:50 +03:00
case Kernel::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
receiver->reply_protected_data = c->data[1]
2009-07-20 01:23:45 +03:00
break
2009-09-07 00:34:50 +03:00
case Kernel::Receiver::GET_ALARM & REQUEST_MASK:
reply_num (receiver->alarm_count)
return
2009-09-07 00:34:50 +03:00
case Kernel::Receiver::SET_ALARM & REQUEST_MASK:
case Kernel::Receiver::ADD_ALARM & REQUEST_MASK:
2009-07-20 01:23:45 +03:00
unsigned old = receiver->alarm_count
2009-09-07 00:34:50 +03:00
if cmd == Kernel::Receiver::SET_ALARM & REQUEST_MASK:
receiver->alarm_count = c->data[1].l
2009-07-20 01:23:45 +03:00
else:
receiver->alarm_count += c->data[1].l
2009-07-20 01:23:45 +03:00
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
2009-05-25 01:31:35 +03:00
default:
2009-09-06 12:04:09 +03:00
dpanic (0, "invalid receiver operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
2009-08-24 22:02:35 +03:00
return
reply_num (0)
2009-05-25 01:31:35 +03:00
2009-09-06 12:04:09 +03:00
static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kMemory *mem = (kMemory *)protected_data.l
switch cmd:
2009-09-07 00:34:50 +03:00
case Kernel::Memory::CREATE & REQUEST_MASK:
switch c->data[0].h:
2009-05-25 01:31:35 +03:00
case CAPTYPE_RECEIVER:
kReceiver *ret = mem->alloc_receiver ()
2009-05-25 01:31:35 +03:00
if ret:
reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
2009-05-25 01:31:35 +03:00
else:
2009-08-24 22:02:35 +03:00
dpanic (0x03311992, "out of memory creating receiver")
2009-09-06 12:04:09 +03:00
reply_num (Kernel::ERR_OUT_OF_MEMORY)
return
2009-05-25 01:31:35 +03:00
case CAPTYPE_MEMORY:
kMemory *ret = mem->alloc_memory ()
2009-05-25 01:31:35 +03:00
if ret:
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
2009-05-25 01:31:35 +03:00
else:
2009-08-24 22:02:35 +03:00
dpanic (0x13311992, "out of memory creating memory")
2009-09-06 12:04:09 +03:00
reply_num (Kernel::ERR_OUT_OF_MEMORY)
return
2009-05-25 01:31:35 +03:00
case CAPTYPE_THREAD:
kThread *ret = mem->alloc_thread (c->data[1].l)
2009-05-25 01:31:35 +03:00
if ret:
reply_cap (CAPTYPE_THREAD | CAP_MASTER, (unsigned)ret, &ret->refs)
2009-05-25 01:31:35 +03:00
else:
2009-08-24 22:02:35 +03:00
dpanic (0x23311992, "out of memory creating thread")
2009-09-06 12:04:09 +03:00
reply_num (Kernel::ERR_OUT_OF_MEMORY)
return
2009-05-25 01:31:35 +03:00
case CAPTYPE_PAGE:
kPage *ret = mem->alloc_page ()
2009-05-25 01:31:35 +03:00
if ret:
reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
2009-05-25 01:31:35 +03:00
else:
2009-08-24 22:02:35 +03:00
dpanic (0x33311992, "out of memory creating page")
2009-09-06 12:04:09 +03:00
reply_num (Kernel::ERR_OUT_OF_MEMORY)
return
case CAPTYPE_CAPS:
kCaps *ret = mem->alloc_caps (c->data[1].l)
2009-05-25 01:31:35 +03:00
if ret:
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
2009-05-25 01:31:35 +03:00
else:
2009-08-24 22:02:35 +03:00
dpanic (0x43311992, "out of memory creating caps")
2009-09-06 12:04:09 +03:00
reply_num (Kernel::ERR_OUT_OF_MEMORY)
return
2009-05-25 01:31:35 +03:00
default:
2009-09-06 12:04:09 +03:00
dpanic (0, "invalid create type")
reply_num (~0)
2009-05-25 01:31:35 +03:00
return
break
2009-09-07 00:34:50 +03:00
case Kernel::Memory::DESTROY & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem:
reply_num (~0)
2009-05-27 15:38:52 +03:00
return
2009-09-06 12:04:09 +03:00
switch (unsigned)c->arg->target & CAPTYPE_MASK:
2009-05-27 15:38:52 +03:00
case CAPTYPE_RECEIVER:
2009-09-06 12:04:09 +03:00
mem->free_receiver ((kReceiver *)c->arg->protected_data.l)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_MEMORY:
2009-09-06 12:04:09 +03:00
mem->free_memory ((kMemory *)c->arg->protected_data.l)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_THREAD:
2009-09-06 12:04:09 +03:00
mem->free_thread ((kThread *)c->arg->protected_data.l)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_PAGE:
2009-09-06 12:04:09 +03:00
mem->free_page ((kPage *)c->arg->protected_data.l)
2009-07-24 15:25:53 +03:00
break
case CAPTYPE_CAPS:
2009-09-06 12:04:09 +03:00
mem->free_caps ((kCaps *)c->arg->protected_data.l)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
default:
panic (0x55228930, "invalid case")
2009-07-24 15:25:53 +03:00
return
2009-05-25 01:31:35 +03:00
break
2009-09-07 00:34:50 +03:00
case Kernel::Memory::LIST & REQUEST_MASK:
2009-05-25 01:31:35 +03:00
// TODO
break
2009-09-07 00:34:50 +03:00
case Kernel::Memory::MAP & REQUEST_MASK:
2009-06-01 02:12:54 +03:00
// FIXME: this should work for fake pages as well.
2009-09-06 12:04:09 +03:00
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
2009-08-24 22:02:35 +03:00
dpanic (0x22993341, "Trying to map non-page")
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
kPage *page = (kPage *)c->arg->protected_data.l
2009-06-01 02:12:54 +03:00
if page->address_space != mem:
2009-08-24 22:02:35 +03:00
dpanic (0x52993341, "Trying to map foreign page")
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
bool readonly = c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY
mem->map (page, c->data[1].l & PAGE_MASK, readonly)
2009-05-25 01:31:35 +03:00
break
2009-09-07 00:34:50 +03:00
case Kernel::Memory::MAPPING & REQUEST_MASK:
bool readonly
kPage *page = mem->get_mapping (c->data[1].l, &readonly)
unsigned t = CAPTYPE_PAGE | CAP_MASTER
if readonly:
2009-09-06 12:04:09 +03:00
t |= Kernel::Page::READONLY
reply_cap (t, (unsigned)page, &page->refs)
return
2009-09-07 00:34:50 +03:00
case Kernel::Memory::GET_LIMIT & REQUEST_MASK:
2009-05-25 01:31:35 +03:00
reply_num (mem->limit)
return
2009-09-07 00:34:50 +03:00
case Kernel::Memory::SET_LIMIT & REQUEST_MASK:
mem->limit = c->data[1].l
2009-05-25 01:31:35 +03:00
break
default:
2009-09-06 12:04:09 +03:00
dpanic (0, "invalid memory operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
return
reply_num (0)
2009-05-25 01:31:35 +03:00
2009-09-06 12:04:09 +03:00
static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kThread *thread = (kThread *)protected_data.l
switch cmd:
2009-09-07 00:34:50 +03:00
case Kernel::Thread::GET_INFO & REQUEST_MASK:
switch c->data[0].h:
2009-09-06 12:04:09 +03:00
case Kernel::Thread::PC:
reply_num (thread->pc)
return
2009-09-06 12:04:09 +03:00
case Kernel::Thread::SP:
reply_num (thread->sp)
return
2009-09-06 12:04:09 +03:00
case Kernel::Thread::FLAGS:
reply_num (thread->flags)
return
default:
reply_num (*kThread_arch_info (thread, c->data[0].h))
return
2009-09-07 00:34:50 +03:00
case Kernel::Thread::SET_INFO & REQUEST_MASK:
2009-05-27 19:33:05 +03:00
unsigned *value
switch c->data[1].l:
2009-09-06 12:04:09 +03:00
case Kernel::Thread::PC:
2009-05-27 19:33:05 +03:00
value = &thread->pc
break
2009-09-06 12:04:09 +03:00
case Kernel::Thread::SP:
2009-05-27 19:33:05 +03:00
value = &thread->sp
break
2009-09-06 12:04:09 +03:00
case Kernel::Thread::FLAGS:
// It is not possible to set the PRIV flag (but it can be reset).
2009-09-06 12:04:09 +03:00
if c->data[1].l & Kernel::Thread::PRIV:
c->data[1].h &= ~Kernel::Thread::PRIV
2009-05-27 19:33:05 +03:00
value = &thread->flags
2009-09-06 12:04:09 +03:00
if c->data[1].h & ~Kernel::Thread::USER_FLAGS:
unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
2009-09-06 12:04:09 +03:00
if (v & Kernel::Thread::WAITING) != (*value & Kernel::Thread::WAITING):
if v & Kernel::Thread::WAITING:
thread->wait ()
2009-05-27 19:33:05 +03:00
else
2009-07-24 15:25:53 +03:00
thread->unwait ()
2009-09-06 12:04:09 +03:00
if (v & Kernel::Thread::RUNNING) != (*value & Kernel::Thread::RUNNING):
if v & Kernel::Thread::RUNNING:
2009-05-27 19:33:05 +03:00
thread->run ()
else
thread->unrun ()
break
default:
value = kThread_arch_info (thread, c->data[1].l)
2009-05-27 19:33:05 +03:00
break
if value:
*value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
2009-05-27 19:33:05 +03:00
break
2009-09-07 00:34:50 +03:00
case Kernel::Thread::USE_SLOT & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if c->data[1].l >= thread->slots || !c->arg.valid ():
2009-09-01 20:00:46 +03:00
dbg_send (5, 3)
2009-08-24 22:02:35 +03:00
dpanic (c->data[1].l, "no argument given for USE_SLOT")
2009-08-19 02:00:05 +03:00
reply_num (~0)
return
// FIXME: This doesn't allow using a fake caps.
2009-09-06 12:04:09 +03:00
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Kernel::Caps::USE):
2009-08-24 22:02:35 +03:00
dpanic (0, "argument for USE_SLOT is not a caps")
2009-08-19 02:00:05 +03:00
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
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
if thread->caps[slot]:
// TODO: invalidate slot.
thread->caps[slot] = new_caps
if new_caps:
// TODO: link it into a list.
break
2009-09-07 00:34:50 +03:00
case Kernel::Thread::GET_CAPS & REQUEST_MASK:
unsigned slot = c->data[1].l
if slot < thread->slots:
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->caps[slot], &thread->caps[slot]->refs, thread->slots)
else:
reply_num (thread->slots)
return
case Kernel::Thread::SCHEDULE & REQUEST_MASK:
2009-07-20 01:23:45 +03:00
do_schedule = true
return
default:
2009-09-06 12:04:09 +03:00
if !(thread->flags & Kernel::Thread::PRIV):
dpanic (0, "invalid thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
2009-08-24 22:02:35 +03:00
return
switch cmd:
2009-09-07 00:34:50 +03:00
case Kernel::Thread::PRIV_REGISTER_INTERRUPT & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
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)
2009-08-24 22:02:35 +03:00
break
2009-09-07 00:34:50 +03:00
case Kernel::Thread::PRIV_GET_TOP_MEMORY & REQUEST_MASK:
2009-08-24 22:02:35 +03:00
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs)
return
2009-09-07 00:34:50 +03:00
case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
2009-08-24 22:02:35 +03:00
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
2009-08-24 22:02:35 +03:00
break
2009-09-07 00:34:50 +03:00
case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
2009-08-24 22:02:35 +03:00
panic (0x54365435, "non-memory argument to alloc_range")
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
kMemory *mem = (kMemory *)c->arg->protected_data.l
2009-08-24 22:02:35 +03:00
if !mem->use (c->data[1].l):
dpanic (0x34365435, "out of memory during alloc_range")
2009-09-06 12:04:09 +03:00
reply_num (Kernel::ERR_OUT_OF_MEMORY)
2009-08-24 22:02:35 +03:00
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")
2009-09-06 12:04:09 +03:00
reply_num (Kernel::ERR_OUT_OF_MEMORY)
2009-08-24 22:02:35 +03:00
return
reply_num (data & ~0xc0000000)
return
2009-09-07 00:34:50 +03:00
case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if !c->arg.valid ():
panic (0x71342134, "no argument provided for alloc physical")
reply_num (~0)
return
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
2009-08-24 22:02:35 +03:00
panic (0x21342134, "no page provided for alloc physical")
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
kPage *page = (kPage *)c->arg->protected_data.l
2009-08-24 22:02:35 +03:00
page->forget ()
if !(c->data[1].l & 2):
2009-09-06 12:04:09 +03:00
if page->flags & Kernel::Page::PAYING:
page->flags &= ~Kernel::Page::PAYING
2009-08-24 22:02:35 +03:00
page->address_space->unuse ()
else:
// This is for mapping allocated ranges. They are already paid for. Record that.
2009-09-06 12:04:09 +03:00
if page->flags & Kernel::Page::PAYING:
2009-08-24 22:02:35 +03:00
page->address_space->unuse ()
else:
2009-09-06 12:04:09 +03:00
page->flags |= Kernel::Page::PAYING
2009-08-24 22:02:35 +03:00
page->frame = c->data[1].l & PAGE_MASK
2009-09-06 12:04:09 +03:00
page->flags |= Kernel::Page::FRAME
2009-08-24 22:02:35 +03:00
if !(c->data[1].l & 1):
2009-09-06 12:04:09 +03:00
page->flags |= Kernel::Page::UNCACHED
2009-08-24 22:02:35 +03:00
if !(c->data[1].l & 2):
2009-09-06 12:04:09 +03:00
page->flags |= Kernel::Page::PHYSICAL
2009-08-24 22:02:35 +03:00
kPage_arch_update_mapping (page)
break
2009-09-07 00:34:50 +03:00
case Kernel::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
2009-08-24 22:02:35 +03:00
dpanic (0x99049380, "invalid page for physical address")
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
kPage *page = (kPage *)c->arg->protected_data.l
2009-08-24 22:02:35 +03:00
reply_num (page->frame & ~0xc0000000)
return
2009-09-07 00:34:50 +03:00
case Kernel::Thread::PRIV_PANIC & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
panic (c->data[1].l, "panic requested by thread")
reply_num (~0)
return
2009-09-07 00:34:50 +03:00
case Kernel::Thread::DBG_SEND & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
dbg_send (c->data[1].l, c->data[1].h)
break
2009-08-24 22:02:35 +03:00
default:
2009-09-06 12:04:09 +03:00
dpanic (0, "invalid priv thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
2009-08-24 22:02:35 +03:00
return
reply_num (0)
return
2009-05-25 01:31:35 +03:00
static bool page_check_payment (kPage *page):
kPage *p
for p = page->share_prev; p; p = p->share_prev:
2009-09-06 12:04:09 +03:00
if p->flags & Kernel::Page::PAYING:
2009-06-01 02:12:54 +03:00
return true
for p = page->share_next; p; p = p->share_next:
2009-09-06 12:04:09 +03:00
if p->flags & Kernel::Page::PAYING:
2009-06-01 02:12:54 +03:00
return true
// No kPage is paying for this frame anymore.
raw_pfree (page->frame)
kPage *next
for p = page->share_prev, next = p->share_prev; p; p = next, next = p->share_prev:
p->frame = NULL
p->share_prev = NULL
p->share_next = NULL
2009-09-06 12:04:09 +03:00
p->flags &= ~(Kernel::Page::SHARED | Kernel::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
2009-09-06 12:04:09 +03:00
p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
kPage_arch_update_mapping (p)
2009-06-01 02:12:54 +03:00
return false
2009-09-06 12:04:09 +03:00
static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kPage *page = (kPage *)protected_data.l
switch cmd & ~Kernel::Page::READONLY:
2009-09-07 00:34:50 +03:00
case Kernel::Page::SHARE & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if !c->arg.valid ():
// Cannot share without a target page.
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
// FIXME: This makes it impossible to use a fake kPage capability.
2009-08-24 22:02:35 +03:00
reply_num (~0)
return
2009-09-06 12:04:09 +03:00
kPage *t = (kPage *)c->arg->protected_data.l
t->forget ()
2009-09-06 12:04:09 +03:00
if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY:
t->flags |= Kernel::Page::READONLY
if !(page->flags & Kernel::Page::FRAME):
break
2009-09-06 12:04:09 +03:00
if c->data[0].h & Kernel::Page::COPY:
if ~t->flags & Kernel::Page::PAYING:
2009-06-01 02:12:54 +03:00
break
2009-09-06 12:04:09 +03:00
if !(c->data[0].h & Kernel::Page::FORGET) || page->flags & Kernel::Page::SHARED:
unsigned *d = (unsigned *)page->frame
2009-06-01 02:12:54 +03:00
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)
2009-06-01 02:12:54 +03:00
else:
2009-09-06 12:04:09 +03:00
t->flags |= Kernel::Page::FRAME
t->frame = raw_zalloc ()
for unsigned i = 0; i <= (c->data[0].h & ~PAGE_MASK); i += 4:
((unsigned *)t->frame)[i >> 2] = d[i >> 2]
else:
if t != page:
t->frame = page->frame
2009-09-06 12:04:09 +03:00
t->flags |= Kernel::Page::FRAME
page->frame = NULL
2009-09-06 12:04:09 +03:00
page->flags &= ~Kernel::Page::FRAME
kPage_arch_update_mapping (page)
kPage_arch_update_mapping (t)
2009-06-01 02:12:54 +03:00
else:
if t == page:
2009-06-01 02:12:54 +03:00
break
2009-09-06 12:04:09 +03:00
if c->data[0].h & Kernel::Page::FORGET:
if ~page->flags & Kernel::Page::SHARED:
if t->flags & Kernel::Page::PAYING:
t->frame = page->frame
2009-09-06 12:04:09 +03:00
t->flags |= Kernel::Page::FRAME
page->frame = NULL
2009-09-06 12:04:09 +03:00
page->flags &= ~Kernel::Page::FRAME
kPage_arch_update_mapping (page)
2009-06-01 02:12:54 +03:00
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)
2009-05-29 00:35:27 +03:00
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
kPage_arch_update_mapping (t)
break
2009-09-07 00:34:50 +03:00
case Kernel::Page::SET_FLAGS & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
if cmd & Kernel::Page::READONLY:
reply_num (~0)
return
2009-06-08 14:46:13 +03:00
// Always refuse to set reserved flags.
2009-09-06 12:04:09 +03:00
c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
2009-06-01 02:12:54 +03:00
// Remember the old flags.
unsigned old = page->flags
2009-06-01 02:12:54 +03:00
// Compute the new flags.
unsigned new_flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
2009-06-01 02:12:54 +03:00
// If we stop paying, see if the frame is still paid for. If not, free it.
2009-09-06 12:04:09 +03:00
if ~new_flags & old & Kernel::Page::PAYING:
// Decrease the use counter in any case.
page->address_space->unuse ()
if !page_check_payment (page):
2009-09-06 12:04:09 +03:00
new_flags &= ~Kernel::Page::FRAME
2009-06-01 02:12:54 +03:00
// If we start paying, increase the use counter.
2009-09-06 12:04:09 +03:00
if new_flags & ~old & Kernel::Page::PAYING:
if !page->address_space->use():
2009-06-01 02:12:54 +03:00
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
2009-09-06 12:04:09 +03:00
new_flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME)
if old & Kernel::Page::FRAME:
new_flags |= Kernel::Page::FRAME
2009-06-01 02:12:54 +03:00
// If we want a frame, see if we can get it.
2009-09-06 12:04:09 +03:00
if ~old & new_flags & Kernel::Page::FRAME:
kPage *p
for p = page; p; p = p->share_prev:
2009-09-06 12:04:09 +03:00
if p->flags & Kernel::Page::PAYING:
break
if !p:
for p = page->share_next; p; p = p->share_next:
2009-09-06 12:04:09 +03:00
if p->flags & Kernel::Page::PAYING:
2009-05-29 00:35:27 +03:00
break
if !p:
2009-09-06 12:04:09 +03:00
new_flags &= ~Kernel::Page::FRAME
2009-06-01 02:12:54 +03:00
// If we can get the new frame, get it.
2009-09-06 12:04:09 +03:00
if ~old & new_flags & Kernel::Page::FRAME:
page->frame = page->address_space->zalloc ()
kPage_arch_update_mapping (page)
2009-05-27 20:29:21 +03:00
break
2009-05-25 01:31:35 +03:00
default:
2009-09-06 12:04:09 +03:00
dpanic (0, "invalid page operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
2009-08-24 22:02:35 +03:00
return
reply_num (0)
static void print_cap (kCapRef cap, kCapRef self):
if cap.deref () == self.deref ():
dbg_log_char ('{')
else:
dbg_log_char ('[')
dbg_log_num ((unsigned)cap.caps)
dbg_log_char (':')
2009-09-01 20:00:46 +03:00
dbg_log_num (cap.index, 1)
if !cap.valid ():
dbg_log_char ('!')
2009-09-06 12:04:09 +03:00
else:
dbg_log_char ('=')
dbg_log_num (cap->protected_data.l)
2009-08-24 22:02:35 +03:00
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
print_cap (c, self)
if cap.deref () == self.deref ():
dbg_log_char ('}')
else:
dbg_log_char (']')
2009-05-25 01:31:35 +03:00
2009-09-06 12:04:09 +03:00
static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
kCaps *caps = (kCapsP)protected_data.l
switch cmd:
2009-09-07 00:34:50 +03:00
case Kernel::Caps::SET & REQUEST_MASK:
2009-09-06 12:04:09 +03:00
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)
return
2009-09-07 00:34:50 +03:00
case Kernel::Caps::PRINT & REQUEST_MASK:
2009-08-24 22:02:35 +03:00
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
dbg_log_char ('\n')
return
2009-05-25 01:31:35 +03:00
default:
2009-09-06 12:04:09 +03:00
dpanic (0, "invalid caps operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
2009-08-24 22:02:35 +03:00
return
2009-05-25 01:31:35 +03:00
2009-09-06 12:04:09 +03:00
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 | Kernel::Receiver::REPLY):
c->invalidate ()
2009-09-06 12:04:09 +03:00
static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapability::Context *c):
2009-05-25 01:31:35 +03:00
// Kernel calling convention:
// data[0].l is the request.
// caps[0] is the reply capability
2009-05-25 01:31:35 +03:00
// other parameters' meanings depend on the operation.
2009-09-06 12:04:09 +03:00
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL_ASYNC):
// This is a call capability. reply is the capability to call. It should be replaced by the reply capability.
((kReceiver *)protected_data.l)->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL)
2009-08-24 22:02:35 +03:00
if must_wait:
old_current->wait ()
2009-09-06 12:04:09 +03:00
if !reply_target:
2009-08-24 22:02:35 +03:00
dpanic (0x54635675, "no target to call")
return
2009-09-06 12:04:09 +03:00
if ((unsigned)reply_target & ~KERNEL_MASK) != 0:
// This is a user-implemented object. Create a real reply capability.
2009-09-06 12:04:09 +03:00
kReceiver *call_target = reply_target
c->reply = kCapRef (&reply_caps, 0)
c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Kernel::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 | Kernel::Receiver::REPLY):
// Reply capability: destroy all before invoke.
2009-09-06 12:04:09 +03:00
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.
2009-09-06 12:04:09 +03:00
kCapRef call_target = c->reply
c->reply.reset ()
reply_target = (kReceiver *)protected_data.l
reply_protected = reply_target->reply_protected_data
2009-09-06 12:04:09 +03:00
kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c)
2009-07-20 01:23:45 +03:00
return
2009-08-24 22:02:35 +03:00
if must_wait:
old_current->wait ()
2009-09-06 12:04:09 +03:00
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
2009-05-29 00:35:27 +03:00
// This is a reply capability.
2009-09-06 12:04:09 +03:00
kReceiver *r = (kReceiver *)protected_data.l
kill_reply (r)
2009-06-10 23:54:12 +03:00
r->send_message (r->reply_protected_data, c)
2009-07-20 01:23:45 +03:00
return
2009-08-24 22:02:35 +03:00
if !target:
return
unsigned cmd
if (target & REQUEST_MASK) == CAP_MASTER:
if c->data[0].l & CAP_MASTER_CREATE:
2009-09-06 12:04:09 +03:00
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:
2009-09-07 00:34:50 +03:00
cmd = target
cmd &= REQUEST_MASK
2009-05-25 01:31:35 +03:00
switch target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER:
2009-09-06 12:04:09 +03:00
receiver_invoke (cmd, target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_MEMORY:
2009-09-06 12:04:09 +03:00
memory_invoke (cmd, target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_THREAD:
2009-09-06 12:04:09 +03:00
thread_invoke (cmd, target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_PAGE:
2009-09-06 12:04:09 +03:00
page_invoke (cmd, target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_CAPS:
2009-09-06 12:04:09 +03:00
caps_invoke (cmd, target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
default:
panic (0x99337744, "invalid capability type invoked")
2009-07-24 15:25:53 +03:00
return
2009-07-20 01:23:45 +03:00
return
2009-05-25 01:31:35 +03:00
2009-09-06 12:04:09 +03:00
void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c):
//log_message ("invoke", (unsigned)target, protected_data.l, c)
2009-05-27 19:33:05 +03:00
if (unsigned)target & ~KERNEL_MASK:
// This is not a kernel capability: send a message to the receiver.
2009-08-24 22:02:35 +03:00
if must_wait:
old_current->wait ()
2009-09-06 12:04:09 +03:00
target->send_message (protected_data, c)
2009-07-20 01:23:45 +03:00
return
2009-05-25 01:31:35 +03:00
// This is a kernel capability. Use a function to allow optimized call capabilities.
2009-09-06 12:04:09 +03:00
context = c
if c->reply.valid ():
reply_target = c->reply->target
reply_protected = c->reply->protected_data
else:
2009-09-06 12:04:09 +03:00
reply_target = NULL
kernel_invoke ((unsigned)target, protected_data, c)