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