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-05-25 01:31:35 +03:00
|
|
|
Capability *Memory::find_capability (unsigned code, bool *copy):
|
|
|
|
*copy = code & 2 ? true : false
|
|
|
|
if code & 1:
|
|
|
|
// Cappage capability
|
|
|
|
unsigned num = (code & ~PAGE_MASK) >> 1
|
|
|
|
if num >= CAPPAGE_SIZE:
|
|
|
|
return NULL
|
|
|
|
Capability *page = (Capability *)(code & PAGE_MASK)
|
|
|
|
for Cappage *p = cappages; p; p = p->next:
|
2009-05-29 00:35:27 +03:00
|
|
|
if p->data.frame == (unsigned)page:
|
2009-05-25 01:31:35 +03:00
|
|
|
return &page[num]
|
|
|
|
else:
|
|
|
|
// Normal capability
|
|
|
|
for Capability *c = capabilities; c; c = c->next:
|
|
|
|
if c == (Capability *)code:
|
|
|
|
return c
|
2009-05-20 23:07:56 +03:00
|
|
|
return NULL
|
|
|
|
|
2009-06-01 02:12:54 +03:00
|
|
|
bool Receiver::try_deliver ():
|
|
|
|
if !messages || !owner || !owner->is_waiting ():
|
|
|
|
return false
|
|
|
|
Message *m = messages
|
|
|
|
if protected_only:
|
|
|
|
for ; m; m = m->next:
|
|
|
|
if m->protected_data == reply_protected_data:
|
|
|
|
break
|
|
|
|
if !m:
|
|
|
|
return false
|
|
|
|
Capability *c[4]
|
|
|
|
for unsigned i = 0; i < 4; ++i:
|
|
|
|
if !m->capabilities[i]:
|
|
|
|
c[i] = NULL
|
|
|
|
else:
|
|
|
|
c[i] = owner->address_space->clone_capability (m->capabilities[i], true)
|
|
|
|
if !c[i]:
|
|
|
|
for unsigned j = 0; j < i; ++j:
|
|
|
|
owner->address_space->free_capability (c[i])
|
|
|
|
return false
|
|
|
|
Thread_arch_receive (owner, m->data, c)
|
|
|
|
owner->unwait ()
|
|
|
|
return true
|
|
|
|
|
|
|
|
bool Receiver::send_message (unsigned protected_data, unsigned data[4], Capability *cap[4], bool copy[4]):
|
|
|
|
bool tried_direct = false
|
|
|
|
if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
|
|
|
|
Capability *c[4]
|
|
|
|
for unsigned i = 0; i < 4; ++i:
|
|
|
|
if !cap[i]:
|
|
|
|
c[i] = NULL
|
|
|
|
else:
|
|
|
|
c[i] = owner->address_space->clone_capability (cap[i], copy[i])
|
|
|
|
if !c[i]:
|
|
|
|
for unsigned j = 0; j < i; ++j:
|
|
|
|
owner->address_space->free_capability (c[i])
|
|
|
|
tried_direct = true
|
|
|
|
break
|
|
|
|
if !tried_direct:
|
|
|
|
Thread_arch_receive (owner, data, c)
|
|
|
|
owner->unwait ()
|
|
|
|
return true
|
|
|
|
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
|
|
|
|
Message *msg = address_space->alloc_message (this, protected_data)
|
|
|
|
if !msg:
|
|
|
|
return false
|
|
|
|
for unsigned i = 0; i < 4; ++i:
|
|
|
|
msg->data[i] = data[i]
|
|
|
|
if !cap[i]:
|
|
|
|
msg->capabilities[i] = NULL
|
|
|
|
else:
|
|
|
|
msg->capabilities[i] = address_space->clone_capability (cap[i], copy[i])
|
|
|
|
if !msg->capabilities[i]:
|
|
|
|
for unsigned j = 0; j < i; ++j:
|
|
|
|
address_space->free_capability (msg->capabilities[j])
|
|
|
|
address_space->free_message (msg)
|
|
|
|
return false
|
|
|
|
if tried_direct:
|
|
|
|
Thread_arch_receive_fail (owner)
|
|
|
|
owner->unwait ()
|
|
|
|
return true
|
|
|
|
|
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-05-25 01:31:35 +03:00
|
|
|
unsigned d[4] = { 0, 0, 0, 0 }
|
|
|
|
Capability *caps[4] = { &r, NULL, NULL, NULL }
|
|
|
|
bool cops[4] = { true, false, false, false }
|
2009-05-27 15:38:52 +03:00
|
|
|
if reply:
|
|
|
|
reply->invoke (d, caps, cops)
|
|
|
|
else:
|
2009-06-01 02:12:54 +03:00
|
|
|
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops)
|
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):
|
|
|
|
unsigned d[4] = { 0, 0, 0, 0 }
|
|
|
|
Capability *caps[4] = { cap, NULL, NULL, NULL }
|
|
|
|
bool cops[4] = { copy, false, false, false }
|
2009-05-27 15:38:52 +03:00
|
|
|
if reply:
|
|
|
|
reply->invoke (d, caps, cops)
|
|
|
|
else:
|
2009-06-01 02:12:54 +03:00
|
|
|
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops)
|
2009-05-25 01:31:35 +03:00
|
|
|
|
|
|
|
static void reply_num (unsigned num):
|
|
|
|
unsigned d[4] = { num, 0, 0, 0 }
|
|
|
|
Capability *caps[4] = { NULL, NULL, NULL, NULL }
|
|
|
|
bool cops[4] = { false, false, false, false }
|
2009-05-27 15:38:52 +03:00
|
|
|
if reply:
|
|
|
|
reply->invoke (d, caps, cops)
|
|
|
|
else:
|
2009-06-01 02:12:54 +03:00
|
|
|
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops)
|
|
|
|
|
|
|
|
static void reply_nums (unsigned num1, unsigned num2):
|
|
|
|
unsigned d[4] = { num1, num2, 0, 0 }
|
|
|
|
Capability *caps[4] = { NULL, NULL, NULL, NULL }
|
|
|
|
bool cops[4] = { false, false, false, false }
|
|
|
|
if reply:
|
|
|
|
reply->invoke (d, caps, cops)
|
|
|
|
else:
|
|
|
|
reply_receiver->send_message (reply_receiver->reply_protected_data, d, caps, cops)
|
2009-05-25 01:31:35 +03:00
|
|
|
|
2009-06-01 02:12:54 +03:00
|
|
|
static void receiver_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned data[4]):
|
2009-05-25 01:31:35 +03:00
|
|
|
Receiver *receiver = (Receiver *)protected_data
|
2009-06-01 02:12:54 +03:00
|
|
|
switch data[0]:
|
2009-05-25 01:31:35 +03:00
|
|
|
case CAP_RECEIVER_SET_OWNER:
|
|
|
|
if ((unsigned)cap->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
|
|
|
|
receiver->own ((Thread *)cap->protected_data)
|
|
|
|
break
|
|
|
|
case CAP_RECEIVER_CREATE_CAPABILITY:
|
2009-06-01 02:12:54 +03:00
|
|
|
reply_cap ((unsigned)receiver, data[1])
|
2009-05-25 01:31:35 +03:00
|
|
|
break
|
|
|
|
case CAP_RECEIVER_CREATE_CALL_CAPABILITY:
|
2009-06-01 02:12:54 +03:00
|
|
|
reply_cap (CAPTYPE_RECEIVER | CAP_RECEIVER_CALL | (data[1] ? CAP_RECEIVER_CALL_ASYNC : 0), protected_data)
|
|
|
|
break
|
|
|
|
case CAP_RECEIVER_GET_REPLY_PROTECTED_DATA:
|
|
|
|
reply_nums (receiver->reply_protected_data, receiver->protected_only ? 1 : 0)
|
|
|
|
break
|
|
|
|
case CAP_RECEIVER_SET_REPLY_PROTECTED_DATA:
|
|
|
|
receiver->reply_protected_data = data[1]
|
|
|
|
receiver->protected_only = data[2]
|
2009-05-25 01:31:35 +03:00
|
|
|
break
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
|
|
|
|
static void memory_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
|
|
|
|
Memory *mem = (Memory *)protected_data
|
|
|
|
switch request:
|
|
|
|
case CAP_MEMORY_CREATE:
|
2009-06-01 02:12:54 +03:00
|
|
|
unsigned rights = data & REQUEST_MASK
|
|
|
|
data &= CAPTYPE_MASK
|
2009-05-25 01:31:35 +03:00
|
|
|
switch data:
|
|
|
|
case CAPTYPE_RECEIVER:
|
|
|
|
Receiver *ret = mem->alloc_receiver ()
|
|
|
|
if ret:
|
2009-06-01 02:12:54 +03:00
|
|
|
reply_cap (data | (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-01 02:12:54 +03:00
|
|
|
reply_cap (data | (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-01 02:12:54 +03:00
|
|
|
reply_cap (data | (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-01 02:12:54 +03:00
|
|
|
reply_cap (data | (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-06-01 02:12:54 +03:00
|
|
|
reply_cap (data | (rights & CAP_CAPPAGE_ALL_RIGHTS), (unsigned)ret)
|
2009-05-25 01:31:35 +03:00
|
|
|
else:
|
|
|
|
reply_num (0)
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
return
|
|
|
|
break
|
|
|
|
case CAP_MEMORY_DESTROY:
|
2009-05-27 15:38:52 +03:00
|
|
|
if !cap || cap->address_space != mem || (unsigned)cap->target & ~KERNEL_MASK:
|
|
|
|
return
|
|
|
|
switch (unsigned)cap->target & CAPTYPE_MASK:
|
|
|
|
case CAPTYPE_RECEIVER:
|
|
|
|
mem->free_receiver ((Receiver *)cap->protected_data)
|
|
|
|
return
|
|
|
|
case CAPTYPE_MEMORY:
|
|
|
|
mem->free_memory ((Memory *)cap->protected_data)
|
|
|
|
return
|
|
|
|
case CAPTYPE_THREAD:
|
|
|
|
mem->free_thread ((Thread *)cap->protected_data)
|
|
|
|
return
|
|
|
|
case CAPTYPE_PAGE:
|
|
|
|
mem->free_page ((Page *)cap->protected_data)
|
|
|
|
return
|
|
|
|
case CAPTYPE_CAPABILITY:
|
|
|
|
mem->free_capability ((Capability *)cap->protected_data)
|
|
|
|
return
|
|
|
|
case CAPTYPE_CAPPAGE:
|
|
|
|
mem->free_cappage ((Cappage *)cap->protected_data)
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
panic (0x55228930, "invalid case")
|
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.
|
|
|
|
if (unsigned)cap->target & ~KERNEL_MASK || ((unsigned)cap->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
|
|
|
|
break
|
|
|
|
Page *page = (Page *)cap->protected_data
|
|
|
|
if page->address_space != mem:
|
|
|
|
break
|
|
|
|
mem->map (page, data & PAGE_MASK, data & (unsigned)cap->target & (1 << CAP_PAGE_WRITE))
|
|
|
|
break
|
2009-05-25 01:31:35 +03:00
|
|
|
case CAP_MEMORY_MAPPING:
|
|
|
|
bool write
|
|
|
|
Page *page = mem->get_mapping (data, &write)
|
|
|
|
unsigned t = CAPTYPE_PAGE | REQUEST_MASK
|
|
|
|
if !write:
|
|
|
|
t &= ~CAP_PAGE_WRITE
|
|
|
|
reply_cap (t, (unsigned)page)
|
|
|
|
break
|
|
|
|
case CAP_MEMORY_SET_LIMIT:
|
|
|
|
mem->limit = data
|
|
|
|
break
|
|
|
|
case CAP_MEMORY_GET_LIMIT:
|
|
|
|
reply_num (mem->limit)
|
|
|
|
break
|
|
|
|
case CAP_MEMORY_DROP:
|
|
|
|
if cap->address_space != mem:
|
|
|
|
break
|
|
|
|
mem->free_capability (cap)
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
|
2009-05-27 19:33:05 +03:00
|
|
|
static void thread_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned data[4]):
|
2009-05-25 01:31:35 +03:00
|
|
|
Thread *thread = (Thread *)protected_data
|
2009-05-27 19:33:05 +03:00
|
|
|
switch data[0]:
|
2009-06-01 02:12:54 +03:00
|
|
|
case CAP_THREAD_INFO:
|
2009-05-27 19:33:05 +03:00
|
|
|
unsigned *value
|
|
|
|
switch data[1]:
|
|
|
|
case CAP_THREAD_INFO_PC:
|
|
|
|
value = &thread->pc
|
|
|
|
break
|
|
|
|
case CAP_THREAD_INFO_SP:
|
|
|
|
value = &thread->sp
|
|
|
|
break
|
|
|
|
case CAP_THREAD_INFO_FLAGS:
|
2009-05-27 20:29:21 +03:00
|
|
|
// It is not possible to set the PRIV flag, but it can be reset.
|
|
|
|
data[2] &= ~THREAD_FLAG_PRIV
|
2009-05-27 19:33:05 +03:00
|
|
|
value = &thread->flags
|
|
|
|
if data[3] & ~THREAD_FLAG_USER:
|
|
|
|
unsigned v = (*value & data[3]) | (data[2] & data[3])
|
|
|
|
if (v & THREAD_FLAG_WAITING) != (*value & THREAD_FLAG_WAITING):
|
|
|
|
if v & THREAD_FLAG_WAITING:
|
|
|
|
thread->wait ()
|
|
|
|
else
|
|
|
|
thread->unwait ()
|
|
|
|
if (v & THREAD_FLAG_RUNNING) != (*value & THREAD_FLAG_RUNNING):
|
|
|
|
if v & THREAD_FLAG_RUNNING:
|
|
|
|
thread->run ()
|
|
|
|
else
|
|
|
|
thread->unrun ()
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
value = Thread_arch_info (thread, data[1])
|
|
|
|
break
|
|
|
|
if value:
|
|
|
|
*value &= ~data[3]
|
|
|
|
*value |= data[2] & data[3]
|
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:
|
|
|
|
schedule ()
|
|
|
|
break
|
2009-06-01 20:22:11 +03:00
|
|
|
case CAP_THREAD_DEBUG:
|
|
|
|
dbg_leds (data[1] & 1, data[1] & 2, data[1] & 4)
|
|
|
|
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.
|
|
|
|
arch_register_interrupt (data[1], cap ? (Receiver *)cap->protected_data : NULL)
|
|
|
|
break
|
|
|
|
case CAP_THREAD_GET_TOP_MEMORY:
|
|
|
|
// Threads with access to this call are trusted, so no sanity checking is done.
|
|
|
|
reply_cap (CAPTYPE_MEMORY | (data[1] & CAP_MEMORY_ALL_RIGHTS), (unsigned)&top_memory)
|
|
|
|
break
|
|
|
|
case CAP_THREAD_MAKE_PRIV:
|
|
|
|
// Threads with access to this call are trusted, so no sanity checking is done.
|
|
|
|
if data[1] & THREAD_FLAG_PRIV:
|
|
|
|
((Thread *)cap->protected_data)->flags |= THREAD_FLAG_PRIV
|
|
|
|
reply_cap (CAPTYPE_THREAD | (data[1] & CAP_THREAD_ALL_PRIV_RIGHTS), cap->protected_data)
|
2009-05-27 19:33:05 +03:00
|
|
|
break
|
2009-06-01 20:22:11 +03:00
|
|
|
case CAP_THREAD_ALLOC_PHYSICAL:
|
|
|
|
// TODO
|
|
|
|
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-05-29 00:35:27 +03:00
|
|
|
static void page_invoke (unsigned target, unsigned protected_data, Capability *cap, bool copy, unsigned data[4]):
|
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
|
|
|
|
switch data[0]:
|
2009-06-01 02:12:54 +03:00
|
|
|
case CAP_PAGE_SHARE:
|
|
|
|
if ((unsigned)cap->target & CAPTYPE_MASK) != (target & CAPTYPE_MASK):
|
|
|
|
// FIXME: This makes it impossible to use a fake Page capability.
|
|
|
|
break
|
|
|
|
if page:
|
|
|
|
Page *t = (Page *)cap->protected_data
|
|
|
|
t->forget ()
|
|
|
|
if data[1] & PAGE_SHARE_READONLY:
|
|
|
|
t->data.flags &= ~PAGE_FLAG_WRITABLE
|
|
|
|
if !page->data.flags & PAGE_FLAG_FRAME:
|
|
|
|
break
|
|
|
|
if data[1] & PAGE_SHARE_COPY:
|
|
|
|
if ~t->data.flags & PAGE_FLAG_PAYING:
|
2009-05-29 00:35:27 +03:00
|
|
|
break
|
2009-06-01 02:12:54 +03:00
|
|
|
if ~data[1] & PAGE_SHARE_FORGET || page->data.flags & PAGE_FLAG_SHARED:
|
|
|
|
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 ()
|
|
|
|
for unsigned i = 0; i <= (data[1] & ~PAGE_MASK); i += 4:
|
|
|
|
((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
|
|
|
|
if data[1] & PAGE_SHARE_FORGET:
|
|
|
|
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:
|
|
|
|
Cappage *t = (Cappage *)cap->protected_data
|
|
|
|
t->forget ()
|
|
|
|
if data[1] & PAGE_SHARE_READONLY:
|
|
|
|
t->data.flags &= ~PAGE_FLAG_WRITABLE
|
|
|
|
if !cappage->data.flags & PAGE_FLAG_FRAME:
|
|
|
|
break
|
|
|
|
if data[1] & PAGE_SHARE_COPY:
|
|
|
|
if ~t->data.flags & PAGE_FLAG_PAYING:
|
|
|
|
break
|
|
|
|
if ~data[1] & PAGE_SHARE_FORGET || cappage->data.flags & PAGE_FLAG_SHARED:
|
|
|
|
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 ()
|
|
|
|
for unsigned i = 0; i < ((data[1] & ~PAGE_MASK) + 1) * sizeof (Capability); i += 4:
|
|
|
|
((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-01 02:12:54 +03:00
|
|
|
if data[1] & PAGE_SHARE_FORGET:
|
|
|
|
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:
|
|
|
|
// Remember the old flags.
|
|
|
|
unsigned old = share_data->flags
|
|
|
|
// Compute the new flags.
|
|
|
|
unsigned new_flags = (share_data->flags & ~data[2]) | (data[1] & data[2])
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
if new_flags & PAGE_FLAG_FRAME:
|
|
|
|
share_data->frame = raw_zalloc ()
|
|
|
|
|
|
|
|
// If the frame is lost, the page is no longer shared.
|
|
|
|
if old & ~new_flags & PAGE_FLAG_FRAME:
|
|
|
|
new_flags &= ~PAGE_FLAG_SHARED
|
|
|
|
if page:
|
|
|
|
if share_data->share_prev:
|
|
|
|
((Page *)share_data->share_prev)->data.share_next = share_data->share_next
|
|
|
|
if share_data->share_next:
|
|
|
|
((Page *)share_data->share_next)->data.share_prev = share_data->share_prev
|
|
|
|
else:
|
|
|
|
if share_data->share_prev:
|
|
|
|
((Cappage *)share_data->share_prev)->data.share_next = share_data->share_next
|
|
|
|
if share_data->share_next:
|
|
|
|
((Cappage *)share_data->share_next)->data.share_prev = share_data->share_prev
|
|
|
|
share_data->share_prev = NULL
|
|
|
|
share_data->share_next = NULL
|
|
|
|
|
|
|
|
// Set the shared flag.
|
|
|
|
if share_data->share_prev || share_data->share_next:
|
|
|
|
new_flags |= PAGE_FLAG_SHARED
|
|
|
|
// Don't allow making shared pages writable.
|
|
|
|
if ~old & PAGE_FLAG_WRITABLE:
|
|
|
|
new_flags &= ~PAGE_FLAG_WRITABLE
|
|
|
|
else:
|
|
|
|
new_flags &= ~PAGE_FLAG_SHARED
|
|
|
|
|
|
|
|
// Actually set the new flags.
|
|
|
|
share_data->flags = new_flags
|
|
|
|
|
|
|
|
// Update mappings if there is a change in writability, or in frame.
|
|
|
|
if page && ((share_data->flags ^ old) & PAGE_FLAG_WRITABLE || (share_data->flags ^ old) & PAGE_FLAG_FRAME):
|
|
|
|
Page_arch_update_mapping (page)
|
|
|
|
reply_num (share_data->flags)
|
2009-05-29 00:35:27 +03:00
|
|
|
break
|
2009-05-25 01:31:35 +03:00
|
|
|
case CAP_CAPPAGE_SET:
|
2009-05-29 00:35:27 +03:00
|
|
|
if !cappage || data[1] >= CAPPAGE_SIZE || !(target & CAP_PAGE_WRITE):
|
2009-05-25 01:31:35 +03:00
|
|
|
return
|
2009-05-29 00:35:27 +03:00
|
|
|
Capability *c = &((Capability *)cappage->data.frame)[data[1]]
|
2009-05-27 20:29:21 +03:00
|
|
|
c->invalidate ()
|
|
|
|
// clone_capability needs a Memory, but doesn't use it when storage is provided.
|
|
|
|
top_memory.clone_capability (cap, copy, c)
|
|
|
|
break
|
2009-05-25 01:31:35 +03:00
|
|
|
default:
|
|
|
|
break
|
|
|
|
|
|
|
|
static void capability_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
|
|
|
|
Capability *capability = (Capability *)protected_data
|
|
|
|
switch request:
|
|
|
|
case CAP_CAPABILITY_GET:
|
|
|
|
reply_cap (capability, true)
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
|
2009-05-29 00:35:27 +03:00
|
|
|
static bool kernel_invoke (unsigned target, unsigned protected_data, unsigned d[4], Capability *c[4], bool copy[4], 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.
|
|
|
|
if !((1 << d[0]) & target & ~REQUEST_MASK):
|
|
|
|
// You are not allowed to perform this operation.
|
2009-05-27 15:38:52 +03:00
|
|
|
return true
|
2009-05-29 00:35:27 +03:00
|
|
|
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_CALL))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)):
|
|
|
|
// This is a call capability.
|
2009-06-01 02:12:54 +03:00
|
|
|
reply_receiver = (Receiver *)protected_data
|
|
|
|
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
|
2009-05-29 00:35:27 +03:00
|
|
|
Capability r
|
|
|
|
Capability *c0 = c[0]
|
|
|
|
if ~(unsigned)c0->target & ~KERNEL_MASK:
|
2009-06-01 02:12:54 +03:00
|
|
|
fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
|
2009-05-29 00:35:27 +03:00
|
|
|
c[0] = &r
|
|
|
|
copy[0] = true
|
|
|
|
bool ret = kernel_invoke ((unsigned)c0->target, c0->protected_data, d, c, copy, c0)
|
|
|
|
r.invalidate ()
|
|
|
|
return ret
|
|
|
|
else:
|
|
|
|
// Kernel call: don't create actual capablities.
|
|
|
|
reply = NULL
|
|
|
|
return kernel_invoke ((unsigned)c0->target, c0->protected_data, d, c, copy, c0)
|
|
|
|
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
|
|
|
|
// This is a reply capability.
|
2009-06-01 02:12:54 +03:00
|
|
|
Receiver *r = (Receiver *)protected_data
|
|
|
|
r->send_message (r->reply_protected_data, d, c, copy)
|
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 ()
|
|
|
|
return true
|
2009-05-25 01:31:35 +03:00
|
|
|
reply = c[0]
|
|
|
|
if d[0] == CAP_DEGRADE:
|
|
|
|
reply_cap (target & d[1], protected_data)
|
|
|
|
return true
|
|
|
|
switch target & CAPTYPE_MASK:
|
|
|
|
case CAPTYPE_RECEIVER:
|
2009-06-01 02:12:54 +03:00
|
|
|
receiver_invoke (target, protected_data, c[1], d)
|
2009-05-25 01:31:35 +03:00
|
|
|
break
|
|
|
|
case CAPTYPE_MEMORY:
|
|
|
|
memory_invoke (target, protected_data, c[1], d[0], d[1])
|
|
|
|
break
|
|
|
|
case CAPTYPE_THREAD:
|
2009-05-27 19:33:05 +03:00
|
|
|
thread_invoke (target, protected_data, c[1], d)
|
2009-05-25 01:31:35 +03:00
|
|
|
break
|
|
|
|
case CAPTYPE_PAGE:
|
2009-05-29 00:35:27 +03:00
|
|
|
page_invoke (target, protected_data, c[1], copy[1], d)
|
2009-05-25 01:31:35 +03:00
|
|
|
break
|
|
|
|
case CAPTYPE_CAPABILITY:
|
|
|
|
capability_invoke (target, protected_data, c[1], d[0], d[1])
|
|
|
|
break
|
|
|
|
case CAPTYPE_CAPPAGE:
|
2009-05-29 00:35:27 +03:00
|
|
|
page_invoke (target, protected_data, c[1], copy[1], d)
|
2009-05-25 01:31:35 +03:00
|
|
|
break
|
|
|
|
default:
|
|
|
|
panic (0x99337744, "invalid capability type invoked")
|
|
|
|
return true
|
|
|
|
|
2009-05-27 19:33:05 +03:00
|
|
|
bool Capability::invoke (unsigned data[4], Capability *cap[4], bool copy[4]):
|
|
|
|
if (unsigned)target & ~KERNEL_MASK:
|
|
|
|
// This is not a kernel capability: send a message to the receiver.
|
|
|
|
return target->send_message (protected_data, data, cap, copy)
|
2009-05-25 01:31:35 +03:00
|
|
|
// This is a kernel capability. Use a function to allow optimized call capabilities.
|
2009-05-29 00:35:27 +03:00
|
|
|
return kernel_invoke ((unsigned)target, protected_data, data, cap, copy, this)
|