#pypp 0 #include "kernel.hh" 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: if p->page == page: return &page[num] else: // Normal capability for Capability *c = capabilities; c; c = c->next: if c == (Capability *)code: return c return NULL static Capability *reply static Receiver *reply_receiver static void reply_cap (unsigned target, unsigned protected_data): Capability r 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. top_memory.alloc_capability ((Receiver *)target, NULL, ref, protected_data, &r) unsigned d[4] = { 0, 0, 0, 0 } Capability *caps[4] = { &r, NULL, NULL, NULL } bool cops[4] = { true, false, false, false } if reply: reply->invoke (d, caps, cops) else: // TODO: send message to reply_receiver 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 } if reply: reply->invoke (d, caps, cops) else: // TODO: send message to reply_receiver 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 } if reply: reply->invoke (d, caps, cops) else: // TODO: send message to reply_receiver static void admin_invoke (unsigned target, Capability *cap, unsigned request, unsigned data): switch request: case CAP_ADMIN_SCHEDULE: schedule () break default: break static void receiver_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data): Receiver *receiver = (Receiver *)protected_data switch request: case CAP_RECEIVER_SET_OWNER: if ((unsigned)cap->target & (CAPTYPE_MASK | ~KERNEL_MASK)) != CAPTYPE_THREAD: // FIXME: This makes it impossible to use a fake thread capability. return receiver->own ((Thread *)cap->protected_data) break case CAP_RECEIVER_CREATE_CAPABILITY: reply_cap ((unsigned)receiver, data) break case CAP_RECEIVER_CREATE_CALL_CAPABILITY: reply_cap (CAPTYPE_RECEIVER | CAP_RECEIVER_CALL, protected_data) 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: switch data: case CAPTYPE_RECEIVER: Receiver *ret = mem->alloc_receiver () if ret: reply_cap (data | REQUEST_MASK, (unsigned)ret) else: reply_num (0) break case CAPTYPE_MEMORY: Memory *ret = mem->alloc_memory () if ret: reply_cap (data | REQUEST_MASK, (unsigned)ret) else: reply_num (0) break case CAPTYPE_THREAD: Thread *ret = mem->alloc_thread () if ret: reply_cap (data | REQUEST_MASK, (unsigned)ret) else: reply_num (0) break case CAPTYPE_PAGE: Page *ret = mem->alloc_page () if ret: reply_cap (data | REQUEST_MASK, (unsigned)ret) else: reply_num (0) break case CAPTYPE_CAPPAGE: Cappage *ret = mem->alloc_cappage () if ret: reply_cap (data | REQUEST_MASK, (unsigned)ret) else: reply_num (0) break default: return break case CAP_MEMORY_DESTROY: if !cap || cap->address_space != mem || (unsigned)cap->target & ~KERNEL_MASK: return switch (unsigned)cap->target & CAPTYPE_MASK: case CAPTYPE_ADMIN: // Admin capabilities don't take space, so they cannot be destroyed. return 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") break case CAP_MEMORY_LIST: // TODO break 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 static void thread_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data): Thread *thread = (Thread *)protected_data switch request: case CAP_THREAD_RUN: if data: thread->run () else: thread->unrun () break case CAP_THREAD_GET_INFO: // TODO case CAP_THREAD_SET_INFO: // TODO default: break static void page_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data): Page *page Cappage *cappage if (target & CAPTYPE_MASK) == CAPTYPE_PAGE: page = (Page *)protected_data cappage = NULL else: page = NULL cappage = (Cappage *)protected_data switch request: case CAP_PAGE_MAP: if !page: return // TODO case CAP_PAGE_SHARE: // TODO case CAP_PAGE_SHARE_COW: // TODO case CAP_PAGE_FORGET: // TODO case CAP_CAPPAGE_SET: if !cappage: return // TODO 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 case CAP_CAPABILITY_SET_DEATH_NOTIFY: // TODO default: break static bool kernel_invoke (unsigned target, unsigned protected_data, unsigned d[4], Capability *c[4], bool copy[4]): // 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. return true reply = c[0] if d[0] == CAP_DEGRADE: reply_cap (target & d[1], protected_data) return true switch target & CAPTYPE_MASK: case CAPTYPE_ADMIN: admin_invoke (target, c[1], d[0], d[1]) break case CAPTYPE_RECEIVER: if target & (1 << CAP_RECEIVER_CALL): // This is a call capability. protected_data = c[0]->protected_data target = (unsigned)c[0]->target if ~(unsigned)c[0]->target & ~KERNEL_MASK: // TODO: create reply capability. else: // Kernel call: don't create actual capablities. reply = NULL reply_receiver = (Receiver *)protected_data return kernel_invoke (target, protected_data, d, c, copy) if target & (1 << CAP_RECEIVER_REPLY): // This is a reply capability. // TODO return true receiver_invoke (target, protected_data, c[1], d[0], d[1]) break case CAPTYPE_MEMORY: memory_invoke (target, protected_data, c[1], d[0], d[1]) break case CAPTYPE_THREAD: thread_invoke (target, protected_data, c[1], d[0], d[1]) break case CAPTYPE_PAGE: page_invoke (target, protected_data, c[1], d[0], d[1]) break case CAPTYPE_CAPABILITY: capability_invoke (target, protected_data, c[1], d[0], d[1]) break case CAPTYPE_CAPPAGE: page_invoke (target, protected_data, c[1], d[0], d[1]) break default: panic (0x99337744, "invalid capability type invoked") return true 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. bool tried_direct = false if target->owner && target->owner->is_waiting (): Capability *c[4] for unsigned i = 0; i < 4; ++i: if !cap[i]: c[i] = NULL else: c[i] = target->owner->address_space->clone_capability (cap[i], copy[i]) if !c[i]: for unsigned j = 0; j < i; ++j: target->owner->address_space->free_capability (c[i]) tried_direct = true break if !tried_direct: Thread_arch_receive (target->owner, data, c) target->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 = target->address_space->alloc_message (this) 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] = target->address_space->clone_capability (cap[i], copy[i]) if !msg->capabilities[i]: for unsigned j = 0; j < i; ++j: target->address_space->free_capability (msg->capabilities[j]) target->address_space->free_message (msg) return false if tried_direct: Thread_arch_receive_fail (target->owner) target->owner->unwait () return true // This is a kernel capability. Use a function to allow optimized call capabilities. return kernel_invoke ((unsigned)target, protected_data, data, cap, copy)