1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-04 23:19:41 +02:00
iris/invoke.ccp

840 lines
28 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-07-25 01:54:12 +03:00
void Thread::raise (unsigned code, unsigned data):
dbg_log ("raise ")
dbg_log_num ((unsigned)current)
dbg_log_char ('/')
if code < NUM_EXCEPTION_CODES:
dbg_log (exception_name[code])
else:
dbg_log ("invalid code:")
dbg_log_num (code)
dbg_log_char ('/')
dbg_log_num (data)
dbg_log_char ('\n')
unrun ()
if !exception.target:
return
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL
c.copy[i] = false
c.data[0] = code
c.data[1] = data
c.data[2] = 0
c.data[3] = 0
exception.invoke (&c)
2009-07-05 11:52:44 +03:00
// From user-provided, thus untrusted, data, find a capability.
2009-05-25 01:31:35 +03:00
Capability *Memory::find_capability (unsigned code, bool *copy):
*copy = code & 2 ? true : false
2009-07-20 01:23:45 +03:00
if !(code & ~3):
return NULL
2009-05-25 01:31:35 +03:00
if code & 1:
// Cappage capability
2009-06-14 00:15:37 +03:00
unsigned num = (code & ~PAGE_MASK) >> 2
2009-05-25 01:31:35 +03:00
if num >= CAPPAGE_SIZE:
2009-07-25 01:54:12 +03:00
dbg_log_num ((unsigned)old_current)
dbg_log (": invalid cappage index ")
dbg_log_num (num)
dbg_log_char ('\n')
2009-05-25 01:31:35 +03:00
return NULL
2009-07-20 01:23:45 +03:00
unsigned page = code & PAGE_MASK
2009-05-25 01:31:35 +03:00
for Cappage *p = cappages; p; p = p->next:
2009-07-20 01:23:45 +03:00
if p->data.frame == page:
return p->cap (num)
2009-05-25 01:31:35 +03:00
else:
// Normal capability
2009-07-20 01:23:45 +03:00
Capability *target = (Capability *)(code & ~3)
2009-05-25 01:31:35 +03:00
for Capability *c = capabilities; c; c = c->next:
2009-07-20 01:23:45 +03:00
if c == target:
2009-05-25 01:31:35 +03:00
return c
2009-07-25 01:54:12 +03:00
dbg_log_num ((unsigned)old_current)
dbg_log (": invalid capability ")
dbg_log_num (code)
dbg_log_char ('\n')
2009-05-20 23:07:56 +03:00
return NULL
2009-07-05 11:52:44 +03:00
// Try to deliver a message.
2009-06-01 02:12:54 +03:00
bool Receiver::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
Message *m = last_message
2009-06-01 02:12:54 +03:00
if protected_only:
2009-07-20 01:23:45 +03:00
for ; m; m = m->prev:
2009-06-01 02:12:54 +03:00
if m->protected_data == reply_protected_data:
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-06-10 23:54:12 +03:00
Capability::Context c
2009-06-01 02:12:54 +03:00
for unsigned i = 0; i < 4; ++i:
2009-07-20 01:23:45 +03:00
c.data[i] = m->data[i]
2009-06-10 23:54:12 +03:00
if m->capabilities[i]:
c.cap[i] = owner->address_space->clone_capability (m->capabilities[i], true)
if !c.cap[i]:
2009-07-25 01:54:12 +03:00
owner->raise (ERR_OUT_OF_MEMORY, 0)
2009-06-01 02:12:54 +03:00
for unsigned j = 0; j < i; ++j:
2009-06-10 23:54:12 +03:00
owner->address_space->free_capability (c.cap[i])
2009-06-01 02:12:54 +03:00
return false
2009-07-20 01:23:45 +03:00
else:
c.cap[i] = NULL
2009-06-10 23:54:12 +03:00
Thread_arch_receive (owner, m->protected_data, &c)
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-06-10 23:54:12 +03:00
bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
2009-06-01 02:12:54 +03:00
bool tried_direct = false
if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
2009-07-20 01:23:45 +03:00
Capability *orig[4]
2009-06-01 02:12:54 +03:00
for unsigned i = 0; i < 4; ++i:
2009-06-10 23:54:12 +03:00
if c->cap[i]:
2009-07-20 01:23:45 +03:00
orig[i] = c->cap[i]
c->cap[i] = owner->address_space->clone_capability (orig[i], c->copy[i])
2009-06-10 23:54:12 +03:00
if !c->cap[i]:
2009-07-25 01:54:12 +03:00
owner->raise (ERR_OUT_OF_MEMORY, 0)
2009-06-01 02:12:54 +03:00
for unsigned j = 0; j < i; ++j:
2009-07-20 01:23:45 +03:00
owner->address_space->free_capability (c->cap[j])
c->cap[j] = orig[j]
c->cap[i] = orig[i]
2009-07-25 01:54:12 +03:00
return false
if protected_data == reply_protected_data:
protected_only = false
Thread_arch_receive (owner, protected_data, c)
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.
2009-07-20 01:23:45 +03:00
Message *msg = address_space->alloc_message (this)
2009-06-01 02:12:54 +03:00
if !msg:
2009-07-25 01:54:12 +03:00
if owner:
owner->raise (ERR_OUT_OF_MEMORY, 0)
2009-06-01 02:12:54 +03:00
return false
2009-07-20 01:23:45 +03:00
msg->protected_data = protected_data
if protected_data == reply_protected_data:
// Put this message in the end (where it will be first seen). Clear the protected_only flag.
protected_only = false
if msg->next:
msg->next->prev = NULL
messages = msg->next
msg->next = NULL
msg->prev = last_message
msg->prev->next = msg
last_message = msg
2009-06-01 02:12:54 +03:00
for unsigned i = 0; i < 4; ++i:
2009-06-10 23:54:12 +03:00
msg->data[i] = c->data[i]
if !c->cap[i]:
2009-06-01 02:12:54 +03:00
msg->capabilities[i] = NULL
else:
2009-06-10 23:54:12 +03:00
msg->capabilities[i] = address_space->clone_capability (c->cap[i], c->copy[i])
2009-06-01 02:12:54 +03:00
if !msg->capabilities[i]:
2009-07-25 01:54:12 +03:00
if owner:
owner->raise (ERR_OUT_OF_MEMORY, 0)
2009-06-01 02:12:54 +03:00
for unsigned j = 0; j < i; ++j:
address_space->free_capability (msg->capabilities[j])
2009-07-20 01:23:45 +03:00
address_space->free_message (this, msg)
2009-06-01 02:12:54 +03:00
return false
return true
2009-05-25 01:31:35 +03:00
static Capability *reply
2009-05-27 15:38:52 +03:00
static Receiver *reply_receiver
2009-05-25 01:31:35 +03:00
2009-05-27 19:33:05 +03:00
static void fill_cap (Capability *r, unsigned target, unsigned protected_data):
2009-05-25 01:31:35 +03:00
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.
2009-05-27 19:33:05 +03:00
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)
2009-06-08 14:46:13 +03:00
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.data[i] = 0
c.cap[0] = &r
c.copy[0] = true
for unsigned i = 1; i < 4; ++i:
c.cap[i] = NULL
c.copy[i] = false
2009-05-27 15:38:52 +03:00
if reply:
2009-06-08 14:46:13 +03:00
reply->invoke (&c)
else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
2009-05-27 19:33:05 +03:00
r.invalidate ()
2009-05-25 01:31:35 +03:00
static void reply_cap (Capability *cap, bool copy):
2009-06-08 14:46:13 +03:00
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.data[i] = 0
c.cap[0] = cap
c.copy[0] = copy
for unsigned i = 1; i < 4; ++i:
c.cap[i] = NULL
c.copy[i] = false
2009-05-27 15:38:52 +03:00
if reply:
2009-06-08 14:46:13 +03:00
reply->invoke (&c)
else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
2009-05-25 01:31:35 +03:00
2009-07-20 01:23:45 +03:00
static void reply_cappage (Cappage *cap, unsigned target):
Capability r
fill_cap (&r, target, (unsigned)cap)
Capability::Context c
for unsigned i = 1; i < 4; ++i:
c.data[i] = 0
c.cap[i] = NULL
c.copy[i] = false
c.data[0] = cap->data.frame
c.cap[0] = &r
c.copy[0] = true
if reply:
reply->invoke (&c)
else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
2009-05-25 01:31:35 +03:00
static void reply_num (unsigned num):
2009-06-08 14:46:13 +03:00
Capability::Context c
c.data[0] = num
for unsigned i = 1; i < 4; ++i:
c.data[i] = 0
for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL
c.copy[i] = false
2009-05-27 15:38:52 +03:00
if reply:
2009-06-08 14:46:13 +03:00
reply->invoke (&c)
else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
2009-06-01 02:12:54 +03:00
static void reply_nums (unsigned num1, unsigned num2):
2009-06-08 14:46:13 +03:00
Capability::Context c
c.data[0] = num1
c.data[1] = num2
c.data[2] = 0
c.data[3] = 0
for unsigned i = 0; i < 4; ++i:
c.cap[i] = NULL
c.copy[i] = false
2009-06-01 02:12:54 +03:00
if reply:
2009-06-08 14:46:13 +03:00
reply->invoke (&c)
else if reply_receiver:
reply_receiver->send_message (reply_receiver->reply_protected_data, &c)
2009-05-25 01:31:35 +03:00
2009-06-08 14:46:13 +03:00
static void receiver_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
2009-05-25 01:31:35 +03:00
Receiver *receiver = (Receiver *)protected_data
2009-06-08 14:46:13 +03:00
switch c->data[0]:
2009-05-25 01:31:35 +03:00
case CAP_RECEIVER_SET_OWNER:
2009-06-08 14:46:13 +03:00
if !c->cap[0] || ((unsigned)c->cap[0]->target & (CAPTYPE_MASK | ~KERNEL_MASK)) != CAPTYPE_THREAD:
2009-06-01 02:12:54 +03:00
// FIXME: This makes it impossible to use a fake Thread capability.
2009-05-25 01:31:35 +03:00
return
2009-06-08 14:46:13 +03:00
receiver->own ((Thread *)c->cap[0]->protected_data)
2009-05-25 01:31:35 +03:00
break
case CAP_RECEIVER_CREATE_CAPABILITY:
2009-06-08 14:46:13 +03:00
reply_cap ((unsigned)receiver, c->data[1])
2009-05-25 01:31:35 +03:00
break
case CAP_RECEIVER_CREATE_CALL_CAPABILITY:
2009-06-08 14:46:13 +03:00
reply_cap (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL) | (c->data[1] ? 1 << CAP_RECEIVER_CALL_ASYNC : 0), protected_data)
2009-06-01 02:12:54 +03:00
break
2009-07-20 01:23:45 +03:00
case CAP_RECEIVER_REPLY_PROTECTED_DATA:
2009-06-01 02:12:54 +03:00
reply_nums (receiver->reply_protected_data, receiver->protected_only ? 1 : 0)
2009-07-20 01:23:45 +03:00
if c->data[1]:
receiver->reply_protected_data = c->data[2]
break
case CAP_RECEIVER_ALARM:
unsigned old = receiver->alarm_count
reply_num (old)
if c->data[1]:
receiver->alarm_count = c->data[2]
else:
receiver->alarm_count += c->data[2]
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
2009-05-25 01:31:35 +03:00
break
default:
break
2009-06-08 14:46:13 +03:00
static void memory_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
2009-05-25 01:31:35 +03:00
Memory *mem = (Memory *)protected_data
2009-06-08 14:46:13 +03:00
switch c->data[0]:
2009-05-25 01:31:35 +03:00
case CAP_MEMORY_CREATE:
2009-06-08 14:46:13 +03:00
unsigned rights = c->data[1] & REQUEST_MASK
unsigned type = c->data[1] & CAPTYPE_MASK
switch type:
2009-05-25 01:31:35 +03:00
case CAPTYPE_RECEIVER:
Receiver *ret = mem->alloc_receiver ()
if ret:
2009-06-08 14:46:13 +03:00
reply_cap (CAPTYPE_RECEIVER | (rights & CAP_RECEIVER_ALL_RIGHTS), (unsigned)ret)
2009-05-25 01:31:35 +03:00
else:
reply_num (0)
break
case CAPTYPE_MEMORY:
Memory *ret = mem->alloc_memory ()
if ret:
2009-06-08 14:46:13 +03:00
reply_cap (CAPTYPE_MEMORY | (rights & CAP_MEMORY_ALL_RIGHTS), (unsigned)ret)
2009-05-25 01:31:35 +03:00
else:
reply_num (0)
break
case CAPTYPE_THREAD:
Thread *ret = mem->alloc_thread ()
if ret:
2009-06-08 14:46:13 +03:00
reply_cap (CAPTYPE_THREAD | (rights & CAP_THREAD_ALL_RIGHTS), (unsigned)ret)
2009-05-25 01:31:35 +03:00
else:
reply_num (0)
break
case CAPTYPE_PAGE:
Page *ret = mem->alloc_page ()
if ret:
2009-06-08 14:46:13 +03:00
reply_cap (CAPTYPE_PAGE | (rights & CAP_PAGE_ALL_RIGHTS), (unsigned)ret)
2009-05-25 01:31:35 +03:00
else:
reply_num (0)
break
case CAPTYPE_CAPPAGE:
Cappage *ret = mem->alloc_cappage ()
if ret:
2009-07-20 01:23:45 +03:00
reply_cappage (ret, CAPTYPE_CAPPAGE | (rights & CAP_CAPPAGE_ALL_RIGHTS))
2009-05-25 01:31:35 +03:00
else:
reply_num (0)
break
default:
return
break
case CAP_MEMORY_DESTROY:
2009-06-08 14:46:13 +03:00
if !c->cap[0] || c->cap[0]->address_space != mem || (unsigned)c->cap[0]->target & ~KERNEL_MASK:
2009-05-27 15:38:52 +03:00
return
2009-06-08 14:46:13 +03:00
switch (unsigned)c->cap[0]->target & CAPTYPE_MASK:
2009-05-27 15:38:52 +03:00
case CAPTYPE_RECEIVER:
2009-06-08 14:46:13 +03:00
mem->free_receiver ((Receiver *)c->cap[0]->protected_data)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_MEMORY:
2009-06-08 14:46:13 +03:00
mem->free_memory ((Memory *)c->cap[0]->protected_data)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_THREAD:
2009-06-08 14:46:13 +03:00
mem->free_thread ((Thread *)c->cap[0]->protected_data)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_PAGE:
2009-06-08 14:46:13 +03:00
mem->free_page ((Page *)c->cap[0]->protected_data)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_CAPABILITY:
2009-06-08 14:46:13 +03:00
mem->free_capability ((Capability *)c->cap[0]->protected_data)
2009-07-24 15:25:53 +03:00
break
2009-05-27 15:38:52 +03:00
case CAPTYPE_CAPPAGE:
2009-06-08 14:46:13 +03:00
mem->free_cappage ((Cappage *)c->cap[0]->protected_data)
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
case CAP_MEMORY_LIST:
// TODO
break
2009-06-01 02:12:54 +03:00
case CAP_MEMORY_MAP:
// FIXME: this should work for fake pages as well.
2009-06-08 14:46:13 +03:00
if !c->cap[0] || (unsigned)c->cap[0]->target & ~KERNEL_MASK || ((unsigned)c->cap[0]->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
2009-06-01 02:12:54 +03:00
break
2009-06-08 14:46:13 +03:00
Page *page = (Page *)c->cap[0]->protected_data
2009-06-01 02:12:54 +03:00
if page->address_space != mem:
break
2009-06-08 14:46:13 +03:00
bool writable = c->data[1] & (unsigned)c->cap[0]->target & (1 << CAP_PAGE_WRITE)
mem->map (page, c->data[1] & PAGE_MASK, writable)
2009-06-01 02:12:54 +03:00
break
2009-05-25 01:31:35 +03:00
case CAP_MEMORY_MAPPING:
bool write
2009-06-08 14:46:13 +03:00
Page *page = mem->get_mapping (c->data[1], &write)
2009-05-25 01:31:35 +03:00
unsigned t = CAPTYPE_PAGE | REQUEST_MASK
if !write:
t &= ~CAP_PAGE_WRITE
reply_cap (t, (unsigned)page)
break
case CAP_MEMORY_LIMIT:
2009-05-25 01:31:35 +03:00
reply_num (mem->limit)
if c->data[2]:
mem->limit = c->data[1]
2009-05-25 01:31:35 +03:00
break
case CAP_MEMORY_DROP:
2009-06-08 14:46:13 +03:00
if !c->cap[0] || c->cap[0]->address_space != mem:
2009-05-25 01:31:35 +03:00
break
2009-06-08 14:46:13 +03:00
mem->free_capability (c->cap[0])
2009-05-25 01:31:35 +03:00
break
default:
break
2009-06-08 14:46:13 +03:00
static void thread_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
2009-05-25 01:31:35 +03:00
Thread *thread = (Thread *)protected_data
2009-06-08 14:46:13 +03:00
switch c->data[0]:
2009-06-01 02:12:54 +03:00
case CAP_THREAD_INFO:
2009-05-27 19:33:05 +03:00
unsigned *value
2009-06-08 14:46:13 +03:00
switch c->data[1]:
2009-05-27 19:33:05 +03:00
case CAP_THREAD_INFO_PC:
value = &thread->pc
break
case CAP_THREAD_INFO_SP:
value = &thread->sp
break
case CAP_THREAD_INFO_FLAGS:
2009-05-27 20:29:21 +03:00
// It is not possible to set the PRIV flag, but it can be reset.
2009-06-08 14:46:13 +03:00
c->data[2] &= ~THREAD_FLAG_PRIV
2009-05-27 19:33:05 +03:00
value = &thread->flags
2009-06-08 14:46:13 +03:00
if c->data[3] & ~THREAD_FLAG_USER:
unsigned v = (*value & c->data[3]) | (c->data[2] & c->data[3])
2009-05-27 19:33:05 +03:00
if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING):
if v & THREAD_FLAG_WAITING:
2009-07-24 15:25:53 +03:00
thread->wait ()
2009-05-27 19:33:05 +03:00
else
2009-07-24 15:25:53 +03:00
thread->unwait ()
2009-05-27 19:33:05 +03:00
if (v & THREAD_FLAG_RUNNING) != (*value & THREAD_FLAG_RUNNING):
if v & THREAD_FLAG_RUNNING:
thread->run ()
else
thread->unrun ()
break
default:
2009-06-08 14:46:13 +03:00
value = Thread_arch_info (thread, c->data[1])
2009-05-27 19:33:05 +03:00
break
if value:
2009-07-05 11:52:44 +03:00
*value = (*value & ~c->data[3]) | (c->data[2] & c->data[3])
2009-06-01 02:12:54 +03:00
reply_num (*value)
else:
reply_num (0)
2009-05-27 19:33:05 +03:00
break
case CAP_THREAD_SCHEDULE:
2009-07-20 01:23:45 +03:00
do_schedule = true
2009-06-01 20:22:11 +03:00
break
2009-05-27 19:33:05 +03:00
case CAP_THREAD_REGISTER_INTERRUPT:
2009-06-01 02:12:54 +03:00
// Threads with access to this call are trusted, so no sanity checking is done.
2009-06-08 14:46:13 +03:00
arch_register_interrupt (c->data[1], c->cap[0] ? (Receiver *)c->cap[0]->protected_data : NULL)
2009-06-01 02:12:54 +03:00
break
case CAP_THREAD_GET_TOP_MEMORY:
// Threads with access to this call are trusted, so no sanity checking is done.
2009-06-08 14:46:13 +03:00
reply_cap (CAPTYPE_MEMORY | (c->data[1] & CAP_MEMORY_ALL_RIGHTS), (unsigned)&top_memory)
2009-06-01 02:12:54 +03:00
break
case CAP_THREAD_MAKE_PRIV:
// Threads with access to this call are trusted, so no sanity checking is done.
2009-06-08 14:46:13 +03:00
if c->data[1] & THREAD_FLAG_PRIV:
((Thread *)c->cap[0]->protected_data)->flags |= THREAD_FLAG_PRIV
reply_cap (CAPTYPE_THREAD | (c->data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), c->cap[0]->protected_data)
2009-05-27 19:33:05 +03:00
break
2009-07-20 01:23:45 +03:00
case CAP_THREAD_ALLOC_RANGE:
// Threads with access to this call are trusted, so not much sanity checking is done.
Memory *mem = (Memory *)c->cap[1]->protected_data
if !mem->use (c->data[1]):
reply_num (0)
break
unsigned data = phys_alloc (c->data[1])
if !data:
mem->unuse (c->data[1])
reply_num (0)
break
reply_num (data - 0x80000000)
break
2009-06-01 20:22:11 +03:00
case CAP_THREAD_ALLOC_PHYSICAL:
2009-06-08 14:46:13 +03:00
// Threads with access to this call are trusted, so no sanity checking is done.
Page *page = (Page *)c->cap[0]->protected_data
page->forget ()
2009-07-20 01:23:45 +03:00
if !(c->data[2] & 2):
if page->data.flags & PAGE_FLAG_PAYING:
page->data.flags &= ~PAGE_FLAG_PAYING
page->address_space->unuse ()
2009-06-08 14:46:13 +03:00
else:
2009-07-20 01:23:45 +03:00
// This is for mapping allocated ranges. They are already paid for. Record that.
if page->data.flags & PAGE_FLAG_PAYING:
page->address_space->unuse ()
else:
page->data.flags |= PAGE_FLAG_PAYING
page->data.frame = c->data[1]
page->data.flags |= PAGE_FLAG_FRAME
if !(c->data[2] & 1):
page->data.flags |= PAGE_FLAG_UNCACHED
if !(c->data[2] & 2):
page->data.flags |= PAGE_FLAG_PHYSICAL
Page_arch_update_mapping (page)
break
case CAP_THREAD_PHYSICAL_ADDRESS:
// Threads with access to this call are trusted, so no sanity checking is done.
Page *page = (Page *)c->cap[1]->protected_data
reply_num (page->data.frame & ~0xc0000000)
2009-06-01 20:22:11 +03:00
break
2009-05-25 01:31:35 +03:00
default:
break
2009-06-01 02:12:54 +03:00
static bool page_check_payment (Page *page):
Page *p
for p = (Page *)page->data.share_prev; p; p = (Page *)p->data.share_prev:
if p->data.flags & PAGE_FLAG_PAYING:
return true
for p = (Page *)page->data.share_next; p; p = (Page *)p->data.share_next:
if p->data.flags & PAGE_FLAG_PAYING:
return true
// No Page is paying for this frame anymore.
raw_pfree (page->data.frame)
Page *next
for p = (Page *)page->data.share_prev, next = (Page *)p->data.share_prev; p; p = next, next = (Page *)p->data.share_prev:
p->data.frame = NULL
p->data.share_prev = NULL
p->data.share_next = NULL
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
Page_arch_update_mapping (p)
for p = page, next = (Page *)p->data.share_next; p; p = next, next = (Page *)p->data.share_next:
p->data.frame = NULL
p->data.share_prev = NULL
p->data.share_next = NULL
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
Page_arch_update_mapping (p)
return false
static bool cappage_check_payment (Cappage *cappage):
Cappage *p
for p = (Cappage *)cappage->data.share_prev; p; p = (Cappage *)p->data.share_prev:
if p->data.flags & PAGE_FLAG_PAYING:
return true
for p = (Cappage *)cappage->data.share_next; p; p = (Cappage *)p->data.share_next:
if p->data.flags & PAGE_FLAG_PAYING:
return true
// No Page is paying for this frame anymore.
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
((Capability *)cappage->data.frame)[i].invalidate ()
raw_pfree (cappage->data.frame)
Cappage *next
for p = (Cappage *)cappage->data.share_prev, next = (Cappage *)p->data.share_prev; p; p = next, next = (Cappage *)p->data.share_prev:
p->data.frame = NULL
p->data.share_prev = NULL
p->data.share_next = NULL
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
for p = cappage, next = (Cappage *)p->data.share_next; p; p = next, next = (Cappage *)p->data.share_next:
p->data.frame = NULL
p->data.share_prev = NULL
p->data.share_next = NULL
p->data.flags &= ~(PAGE_FLAG_SHARED | PAGE_FLAG_FRAME)
return false
2009-06-08 14:46:13 +03:00
static void page_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
2009-05-25 01:31:35 +03:00
Page *page
Cappage *cappage
2009-05-29 00:35:27 +03:00
ShareData *share_data
2009-05-25 01:31:35 +03:00
if (target & CAPTYPE_MASK) == CAPTYPE_PAGE:
page = (Page *)protected_data
cappage = NULL
2009-05-29 00:35:27 +03:00
share_data = &page->data
2009-05-25 01:31:35 +03:00
else:
page = NULL
cappage = (Cappage *)protected_data
2009-05-29 00:35:27 +03:00
share_data = &cappage->data
2009-06-08 14:46:13 +03:00
switch c->data[0]:
2009-06-01 02:12:54 +03:00
case CAP_PAGE_SHARE:
2009-06-08 14:46:13 +03:00
if !c->cap[0] || ((unsigned)c->cap[0]->target & CAPTYPE_MASK) != (target & CAPTYPE_MASK):
2009-06-01 02:12:54 +03:00
// FIXME: This makes it impossible to use a fake Page capability.
break
if page:
2009-06-08 14:46:13 +03:00
Page *t = (Page *)c->cap[0]->protected_data
2009-06-01 02:12:54 +03:00
t->forget ()
2009-06-08 14:46:13 +03:00
if c->data[1] & PAGE_SHARE_READONLY:
2009-06-01 02:12:54 +03:00
t->data.flags &= ~PAGE_FLAG_WRITABLE
if !page->data.flags & PAGE_FLAG_FRAME:
break
2009-06-08 14:46:13 +03:00
if c->data[1] & PAGE_SHARE_COPY:
2009-06-01 02:12:54 +03:00
if ~t->data.flags & PAGE_FLAG_PAYING:
2009-05-29 00:35:27 +03:00
break
2009-06-08 14:46:13 +03:00
if ~c->data[1] & PAGE_SHARE_FORGET || page->data.flags & PAGE_FLAG_SHARED:
2009-06-01 02:12:54 +03:00
unsigned *d = (unsigned *)page->data.frame
if t == page:
Page *other = page->data.share_next ? (Page *)page->data.share_next : (Page *)page->data.share_prev
if !other:
Page_arch_update_mapping (t)
break
if page->data.share_next:
((Page *)page->data.share_next)->data.share_prev = page->data.share_prev
if page->data.share_prev:
((Page *)page->data.share_prev)->data.share_next = page->data.share_next
page->data.share_next = NULL
page->data.share_prev = NULL
page_check_payment (other)
else:
t->data.flags |= PAGE_FLAG_FRAME
t->data.frame = raw_zalloc ()
2009-06-08 14:46:13 +03:00
for unsigned i = 0; i <= (c->data[1] & ~PAGE_MASK); i += 4:
2009-06-01 02:12:54 +03:00
((unsigned *)t->data.frame)[i >> 2] = d[i >> 2]
else:
if t != page:
t->data.frame = page->data.frame
t->data.flags |= PAGE_FLAG_FRAME
page->data.frame = NULL
page->data.flags &= ~PAGE_FLAG_FRAME
Page_arch_update_mapping (page)
Page_arch_update_mapping (t)
else:
if t == page:
break
2009-06-08 14:46:13 +03:00
if c->data[1] & PAGE_SHARE_FORGET:
2009-06-01 02:12:54 +03:00
if ~page->data.flags & PAGE_FLAG_SHARED:
if t->data.flags & PAGE_FLAG_PAYING:
t->data.frame = page->data.frame
t->data.flags |= PAGE_FLAG_FRAME
page->data.frame = NULL
page->data.flags &= ~PAGE_FLAG_FRAME
Page_arch_update_mapping (page)
else:
t->data.share_prev = page->data.share_prev
t->data.share_next = page->data.share_next
if t->data.share_prev:
((Page *)t->data.share_prev)->data.share_next = t
if t->data.share_next:
((Page *)t->data.share_next)->data.share_prev = t
page->data.share_prev = NULL
page->data.share_next = NULL
page->forget ()
page_check_payment (t)
else:
t->data.share_prev = page->data.share_prev
t->data.share_next = page
page->data.share_prev = t
if t->data.share_prev:
((Page *)t->data.share_prev)->data.share_next = t
Page_arch_update_mapping (t)
else:
2009-06-08 14:46:13 +03:00
Cappage *t = (Cappage *)c->cap[0]->protected_data
2009-06-01 02:12:54 +03:00
t->forget ()
2009-06-08 14:46:13 +03:00
if c->data[1] & PAGE_SHARE_READONLY:
2009-06-01 02:12:54 +03:00
t->data.flags &= ~PAGE_FLAG_WRITABLE
if !cappage->data.flags & PAGE_FLAG_FRAME:
break
2009-06-08 14:46:13 +03:00
if c->data[1] & PAGE_SHARE_COPY:
2009-06-01 02:12:54 +03:00
if ~t->data.flags & PAGE_FLAG_PAYING:
break
2009-06-08 14:46:13 +03:00
if ~c->data[1] & PAGE_SHARE_FORGET || cappage->data.flags & PAGE_FLAG_SHARED:
2009-06-01 02:12:54 +03:00
unsigned *d = (unsigned *)cappage->data.frame
if t == cappage:
Cappage *other = cappage->data.share_next ? (Cappage *)cappage->data.share_next : (Cappage *)cappage->data.share_prev
if !other:
break
if cappage->data.share_next:
((Cappage *)cappage->data.share_next)->data.share_prev = cappage->data.share_prev
if cappage->data.share_prev:
((Cappage *)cappage->data.share_prev)->data.share_next = cappage->data.share_next
cappage->data.share_next = NULL
cappage->data.share_prev = NULL
cappage_check_payment (other)
else:
t->data.flags |= PAGE_FLAG_FRAME
t->data.frame = raw_zalloc ()
2009-06-08 14:46:13 +03:00
for unsigned i = 0; i < ((c->data[1] & ~PAGE_MASK) + 1) * sizeof (Capability); i += 4:
2009-06-01 02:12:54 +03:00
((unsigned *)t->data.frame)[i >> 2] = d[i >> 2]
else:
if t != cappage:
t->data.frame = cappage->data.frame
t->data.flags |= PAGE_FLAG_FRAME
cappage->data.frame = NULL
cappage->data.flags &= ~PAGE_FLAG_FRAME
2009-05-29 00:35:27 +03:00
else:
2009-06-01 02:12:54 +03:00
if t == cappage:
2009-05-29 00:35:27 +03:00
break
2009-06-08 14:46:13 +03:00
if c->data[1] & PAGE_SHARE_FORGET:
2009-06-01 02:12:54 +03:00
if ~cappage->data.flags & PAGE_FLAG_SHARED:
if t->data.flags & PAGE_FLAG_PAYING:
t->data.frame = cappage->data.frame
t->data.flags |= PAGE_FLAG_FRAME
cappage->data.frame = NULL
cappage->data.flags &= ~PAGE_FLAG_FRAME
else:
t->data.share_prev = cappage->data.share_prev
t->data.share_next = cappage->data.share_next
if t->data.share_prev:
((Cappage *)t->data.share_prev)->data.share_next = t
if t->data.share_next:
((Cappage *)t->data.share_next)->data.share_prev = t
cappage->data.share_prev = NULL
cappage->data.share_next = NULL
cappage->forget ()
cappage_check_payment (t)
else:
t->data.share_prev = cappage->data.share_prev
t->data.share_next = cappage
cappage->data.share_prev = t
if t->data.share_prev:
((Cappage *)t->data.share_prev)->data.share_next = t
case CAP_PAGE_FLAGS:
2009-06-08 14:46:13 +03:00
// Always refuse to set reserved flags.
c->data[2] &= ~(PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
2009-06-01 02:12:54 +03:00
// Remember the old flags.
unsigned old = share_data->flags
// Compute the new flags.
2009-06-08 14:46:13 +03:00
unsigned new_flags = (share_data->flags & ~c->data[2]) | (c->data[1] & c->data[2])
2009-06-01 02:12:54 +03:00
// If we stop paying, see if the frame is still paid for. If not, free it.
if ~new_flags & old & PAGE_FLAG_PAYING:
if page:
// Decrease the use counter in any case.
page->address_space->unuse ()
if !page_check_payment (page):
new_flags &= ~PAGE_FLAG_FRAME
else:
// Decrease the use counter in any case.
cappage->address_space->unuse ()
if !cappage_check_payment (cappage):
new_flags &= ~PAGE_FLAG_FRAME
// If we start paying, increase the use counter.
if new_flags & ~old & PAGE_FLAG_PAYING:
if !(page ? page->address_space : cappage->address_space)->use():
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
new_flags &= ~(PAGE_FLAG_PAYING | PAGE_FLAG_FRAME)
if old & PAGE_FLAG_FRAME:
new_flags |= PAGE_FLAG_FRAME
// If we want a frame, see if we can get it.
if ~old & new_flags & PAGE_FLAG_FRAME:
2009-05-29 00:35:27 +03:00
if page:
Page *p
2009-06-01 02:12:54 +03:00
for p = page; p; p = (Page *)p->data.share_prev:
2009-05-29 00:35:27 +03:00
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
2009-06-01 02:12:54 +03:00
if !p:
new_flags &= ~PAGE_FLAG_FRAME
2009-05-29 00:35:27 +03:00
else:
Cappage *p
2009-06-01 02:12:54 +03:00
for p = cappage; p; p = (Cappage *)p->data.share_prev:
2009-05-29 00:35:27 +03:00
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
2009-06-01 02:12:54 +03:00
if !p:
new_flags &= ~PAGE_FLAG_FRAME
// If we can get the new frame, get it.
2009-06-10 23:54:12 +03:00
Capability *cap = &((Capability *)cappage->data.frame)[c->data[1]]
cap->invalidate ()
2009-06-10 22:42:01 +03:00
// clone_capability needs a Memory, but doesn't use it when storage is provided.
2009-06-10 23:54:12 +03:00
top_memory.clone_capability (c->cap[0], c->copy[0], cap)
2009-05-27 20:29:21 +03:00
break
2009-05-25 01:31:35 +03:00
default:
break
2009-06-10 23:54:12 +03:00
static void capability_invoke (unsigned target, unsigned protected_data, Capability::Context *c):
2009-05-25 01:31:35 +03:00
Capability *capability = (Capability *)protected_data
2009-06-10 23:54:12 +03:00
switch c->data[0]:
2009-05-25 01:31:35 +03:00
case CAP_CAPABILITY_GET:
reply_cap (capability, true)
break
default:
break
2009-07-20 01:23:45 +03:00
static void kernel_invoke (unsigned target, unsigned protected_data, Capability::Context *c, Capability *self):
2009-05-25 01:31:35 +03:00
// Kernel calling convention:
// data[0] is the request.
// cap[0] is the reply capability
// other parameters' meanings depend on the operation.
2009-05-29 00:35:27 +03:00
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_CALL))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)):
2009-06-14 00:15:37 +03:00
// This is a call capability. cap[0] is the capability to call.
2009-06-01 02:12:54 +03:00
reply_receiver = (Receiver *)protected_data
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
2009-06-10 23:54:12 +03:00
Capability *c0 = c->cap[0]
2009-07-05 11:52:44 +03:00
if c0:
if ((unsigned)c0->target & ~KERNEL_MASK) != 0:
Capability r
fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
c->cap[0] = &r
c->copy[0] = true
c0->target->send_message (c0->protected_data, c)
r.invalidate ()
else:
// Kernel call: don't create actual capablities.
c->cap[0] = NULL
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0)
2009-07-20 01:23:45 +03:00
return
2009-05-29 00:35:27 +03:00
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
// This is a reply capability.
2009-06-01 02:12:54 +03:00
Receiver *r = (Receiver *)protected_data
2009-06-10 23:54:12 +03:00
r->send_message (r->reply_protected_data, c)
2009-05-29 00:35:27 +03:00
while self->parent:
self = self->parent
2009-06-01 02:12:54 +03:00
while self->sibling_prev:
self->sibling_prev->invalidate ()
while self->sibling_next:
self->sibling_next->invalidate ()
2009-05-29 00:35:27 +03:00
self->invalidate ()
2009-07-20 01:23:45 +03:00
return
2009-06-14 00:15:37 +03:00
if !((1 << c->data[0]) & target & REQUEST_MASK):
2009-06-11 00:10:30 +03:00
// You are not allowed to perform this operation.
2009-07-25 01:54:12 +03:00
dbg_log ("operation not allowed: ")
dbg_log_num (c->data[0])
dbg_log ("; target = ")
dbg_log_num (target)
2009-07-20 01:23:45 +03:00
return
2009-06-10 23:54:12 +03:00
reply = c->cap[0]
if c->data[0] == CAP_DEGRADE:
reply_cap (target & c->data[1], protected_data)
2009-07-20 01:23:45 +03:00
return
2009-05-25 01:31:35 +03:00
switch target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER:
2009-06-10 23:54:12 +03:00
receiver_invoke (target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_MEMORY:
2009-06-10 23:54:12 +03:00
memory_invoke (target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_THREAD:
2009-06-10 23:54:12 +03:00
thread_invoke (target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_PAGE:
2009-06-10 23:54:12 +03:00
page_invoke (target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_CAPABILITY:
2009-06-10 23:54:12 +03:00
capability_invoke (target, protected_data, c)
2009-05-25 01:31:35 +03:00
break
case CAPTYPE_CAPPAGE:
2009-06-10 23:54:12 +03:00
page_invoke (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-07-20 01:23:45 +03:00
void Capability::invoke (Capability::Context *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-07-20 01:23:45 +03:00
target->send_message (protected_data, c)
return
2009-05-25 01:31:35 +03:00
// This is a kernel capability. Use a function to allow optimized call capabilities.
2009-07-05 11:52:44 +03:00
reply_receiver = NULL
2009-07-20 01:23:45 +03:00
kernel_invoke ((unsigned)target, protected_data, c, this)