diff --git a/definitions/memory_layout.yaml b/definitions/memory_layout.yaml index 8c76f62..ddf8fe3 100644 --- a/definitions/memory_layout.yaml +++ b/definitions/memory_layout.yaml @@ -13,6 +13,12 @@ - name: heap size: 32G +- name: capsmap + size: 32G + +- name: caps + size: 32G + - name: stacks size: 64G diff --git a/definitions/objects/mailbox.def b/definitions/objects/mailbox.def index 501ee2b..a48c143 100644 --- a/definitions/objects/mailbox.def +++ b/definitions/objects/mailbox.def @@ -14,9 +14,9 @@ object mailbox : object { method close [destructor cap:close] # Asynchronously send a message to the reciever - method send [cap:send handle] { + method send [cap:send] { param tag uint64 - param data buffer [zero_ok] + param subtag uint64 param handles ref object [list] } @@ -24,19 +24,18 @@ object mailbox : object { # arrive if block is true. method receive [cap:receive] { param tag uint64 [out] - param data buffer [out zero_ok] + param subtag uint64 [out] param handles ref object [out list zero_ok] param reply_tag uint16 [out optional] - param badge uint64 [out optional] param flags uint64 } # Send a message to the reciever, and block until a # response is sent. Note that getting this response # does not require the receive capability. - method call [cap:send handle] { + method call [cap:send] { param tag uint64 [inout] - param data buffer [inout zero_ok] + param subtag uint64 [inout] param handles ref object [inout list zero_ok] } @@ -44,7 +43,7 @@ object mailbox : object { # requires the receive capability and not the send capability. method respond [cap:receive] { param tag uint64 - param data buffer [zero_ok] + param subtag uint64 param handles ref object [list zero_ok] param reply_tag uint16 } @@ -54,12 +53,10 @@ object mailbox : object { # capability. method respond_receive [cap:receive] { param tag uint64 [inout] - param data buffer [inout zero_ok] - param data_in size + param subtag uint64 [inout] param handles ref object [inout list zero_ok] param handles_in size param reply_tag uint16 [inout] - param badge uint64 [out optional] param flags uint64 } } diff --git a/definitions/objects/process.def b/definitions/objects/process.def index 3a4ec9f..998fce7 100644 --- a/definitions/objects/process.def +++ b/definitions/objects/process.def @@ -26,6 +26,5 @@ object process : object { # object as the specified handle. method give_handle { param target ref object [handle] # A handle in the caller process to send - param received ref object [out optional] # The handle as the recipient will see it } } diff --git a/definitions/syscalls.def b/definitions/syscalls.def index 654ba3a..fcad59e 100644 --- a/definitions/syscalls.def +++ b/definitions/syscalls.def @@ -32,7 +32,7 @@ interface syscalls [syscall] { # supplied list is not big enough, will set the size # needed in `size` and return j6_err_insufficient function handle_list { - param handles ref object [list inout zero_ok] # A list of handles to be filled + param handles struct handle_descriptor [list inout zero_ok] # A list of handles to be filled } # Create a clone of an existing handle, possibly with diff --git a/src/kernel/capabilities.cpp b/src/kernel/capabilities.cpp new file mode 100644 index 0000000..f6789b6 --- /dev/null +++ b/src/kernel/capabilities.cpp @@ -0,0 +1,62 @@ +#include + +#include "capabilities.h" +#include "memory.h" + +static constexpr size_t one_page_worth = mem::frame_size / sizeof(capability); + +inline j6_handle_t make_handle(size_t &counter) { + //return util::hash(__atomic_fetch_add(&counter, 1, __ATOMIC_RELAXED)); + return __atomic_add_fetch(&counter, 1, __ATOMIC_RELAXED); +} + +cap_table::cap_table(uintptr_t start) : + m_caps(reinterpret_cast(start), one_page_worth), + m_count {0} +{} + +j6_handle_t +cap_table::create(obj::kobject *target, j6_cap_t caps) +{ + j6_handle_t new_handle = make_handle(m_count); + + m_caps.insert({ + new_handle, + j6_handle_invalid, + 0, // starts with a count of 0 holders + caps, + target->get_type(), + target, + }); + + return new_handle; +} + +j6_handle_t +cap_table::derive(j6_handle_t base, j6_cap_t caps) +{ + capability *existing = m_caps.find(base); + if (!existing) + return j6_handle_invalid; + + caps &= existing->caps; + + j6_handle_t new_handle = make_handle(m_count); + + m_caps.insert({ + new_handle, + base, + 0, // starts with a count of 0 holders + caps, + existing->type, + existing->object, + }); + + return new_handle; +} + +capability * +cap_table::find(j6_handle_t id) +{ + return m_caps.find(id); +} diff --git a/src/kernel/capabilities.h b/src/kernel/capabilities.h new file mode 100644 index 0000000..dcf2d86 --- /dev/null +++ b/src/kernel/capabilities.h @@ -0,0 +1,48 @@ +#pragma once +/// \file capabilities.h +/// Capability table definitions + +#include +#include +#include + +#include "objects/kobject.h" + +struct capability +{ + j6_handle_t id; + j6_handle_t parent; + + uint32_t holders; + j6_cap_t caps; + obj::kobject::type type; + // 1 byte alignment padding + + obj::kobject *object; +}; + +class cap_table +{ +public: + /// Constructor. Takes the start of the memory region to contain the cap table. + cap_table(uintptr_t start); + + /// Create a new capability for the given object. + j6_handle_t create(obj::kobject *target, j6_cap_t caps); + + /// Create a new capability from an existing one. + j6_handle_t derive(j6_handle_t id, j6_cap_t caps); + + /// Get the capability referenced by a handle + capability * find(j6_handle_t id); + +private: + using map_type = util::inplace_map; + map_type m_caps; + + util::spinlock m_lock; + size_t m_count; +}; + +extern cap_table &g_cap_table; +inline uint64_t & get_map_key(capability &cap) { return cap.id; } diff --git a/src/kernel/kernel.module b/src/kernel/kernel.module index 4429e4a..69a0aa5 100644 --- a/src/kernel/kernel.module +++ b/src/kernel/kernel.module @@ -11,6 +11,7 @@ kernel = module("kernel", "apic.cpp", "assert.cpp", "boot.s", + "capabilities.cpp", "clock.cpp", "cpprt.cpp", "cpu.cpp", diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 522f75b..4822c27 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -6,6 +6,7 @@ #include #include "assert.h" +#include "capabilities.h" #include "cpu.h" #include "device_manager.h" #include "interrupts.h" @@ -86,7 +87,10 @@ load_init_server(bootproto::program &program, uintptr_t modules_address) using obj::vm_flags; obj::process *p = new obj::process; - p->add_handle(&obj::system::get(), obj::system::init_caps); + + j6_handle_t sys_handle = + g_cap_table.create(&obj::system::get(), obj::system::init_caps); + p->add_handle(sys_handle); vm_space &space = p->space(); for (const auto § : program.sections) { diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 4533e58..b81783c 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -5,6 +5,7 @@ #include #include "assert.h" +#include "capabilities.h" #include "device_manager.h" #include "frame_allocator.h" #include "heap_allocator.h" @@ -31,6 +32,9 @@ uintptr_t g_slabs_bump_pointer; static util::no_construct __g_kernel_heap_storage; heap_allocator &g_kernel_heap = __g_kernel_heap_storage.value; +static util::no_construct __g_cap_table_storage; +cap_table &g_cap_table = __g_cap_table_storage.value; + static util::no_construct __g_frame_allocator_storage; frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value; @@ -40,6 +44,9 @@ obj::vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value; static util::no_construct __g_kernel_heapmap_area_storage; obj::vm_area_untracked &g_kernel_heapmap_area = __g_kernel_heapmap_area_storage.value; +static util::no_construct __g_cap_table_area_storage; +obj::vm_area_untracked &g_cap_table_area = __g_cap_table_area_storage.value; + static util::no_construct __g_kernel_stacks_storage; obj::vm_area_guarded &g_kernel_stacks = __g_kernel_stacks_storage.value; @@ -104,6 +111,13 @@ memory_initialize_pre_ctors(bootproto::args &kargs) new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset}; + obj::vm_area *caps = new (&g_cap_table_area) + obj::vm_area_untracked(mem::caps_size, vm_flags::write); + + vm.add(mem::caps_offset, caps); + + new (&g_cap_table) cap_table {mem::caps_offset}; + obj::vm_area *stacks = new (&g_kernel_stacks) obj::vm_area_guarded { mem::stacks_offset, mem::kernel_stack_pages, diff --git a/src/kernel/objects/handle.h b/src/kernel/objects/handle.h deleted file mode 100644 index 9b07f4b..0000000 --- a/src/kernel/objects/handle.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once -/// \file handle.h -/// Definition of kobject handles - -#include -#include "objects/kobject.h" - -namespace obj { - -struct handle -{ - constexpr static uint64_t id_mask = 0x00000000ffffffff; - constexpr static uint64_t cap_mask = 0x00ffffff00000000; - constexpr static uint64_t type_mask = 0xff00000000000000; - - constexpr static unsigned cap_shift = 32; - constexpr static unsigned type_shift = 56; - - // A j6_handle_t is an id in the low 32 bits, caps in bits 32-55, and type in 56-63 - static inline j6_handle_t make_id(j6_handle_t id, j6_cap_t caps, kobject *obj) { - return (id & 0xffffffffull) | - ((static_cast(caps) << cap_shift) & cap_mask) | - static_cast(obj ? obj->get_type() : kobject::type::none) << type_shift; - } - - inline handle() : id {j6_handle_invalid}, badge {0}, object {nullptr} {} - - inline handle(j6_handle_t in_id, kobject *in_obj, j6_cap_t caps, uint64_t in_badge = 0) : - id {make_id(in_id, caps, in_obj)}, badge {in_badge}, object {in_obj} { - if (object) object->handle_retain(); - } - - inline handle(const handle &o) : - id {o.id}, badge {o.badge}, object {o.object} { - if (object) object->handle_retain(); - } - - inline handle(handle &&o) : - id {o.id}, badge {o.badge}, object {o.object} { - o.id = 0; - o.object = nullptr; - } - - inline handle & operator=(const handle &o) { - if (object) object->handle_release(); - id = o.id; badge = o.badge; object = o.object; - if (object) object->handle_retain(); - return *this; - } - - inline handle & operator=(handle &&o) { - if (object) object->handle_release(); - id = o.id; badge = o.badge; object = o.object; - o.id = 0; o.badge = 0; o.object = nullptr; - return *this; - } - - inline ~handle() { - if (object) object->handle_release(); - } - - inline j6_cap_t caps() const { return (id & cap_mask) >> cap_shift; } - - inline bool has_cap(j6_cap_t test) const { - return (caps() & test) == test; - } - - inline kobject::type type() const { - return static_cast(id >> 56); - } - - inline int compare(const handle &o) { - return id > o.id ? 1 : id < o.id ? -1 : 0; - } - - template - inline T * as() { - if (type() != T::type) return nullptr; - return reinterpret_cast(object); - } - - template - inline const T * as() const { - if (type() != T::type) return nullptr; - return reinterpret_cast(object); - } - - template <> - inline kobject * as() { return object; } - - template <> - inline const kobject * as() const { return object; } - - j6_handle_t id; - uint64_t badge; - kobject *object; -}; - -} // namespace obj diff --git a/src/kernel/objects/mailbox.cpp b/src/kernel/objects/mailbox.cpp index 84855d8..e358b29 100644 --- a/src/kernel/objects/mailbox.cpp +++ b/src/kernel/objects/mailbox.cpp @@ -1,6 +1,5 @@ #include -#include "objects/handle.h" #include "objects/mailbox.h" #include "objects/thread.h" diff --git a/src/kernel/objects/mailbox.h b/src/kernel/objects/mailbox.h index 1a9c6fc..be09bdc 100644 --- a/src/kernel/objects/mailbox.h +++ b/src/kernel/objects/mailbox.h @@ -7,7 +7,6 @@ #include #include -#include "objects/handle.h" #include "objects/kobject.h" #include "slab_allocated.h" #include "wait_queue.h" @@ -26,11 +25,8 @@ public: static constexpr kobject::type type = kobject::type::mailbox; - /// Max message data length - constexpr static size_t max_data_length = 88; - /// Max message handle count - constexpr static size_t max_handle_count = 6; + constexpr static size_t max_handle_count = 5; struct message; @@ -91,18 +87,12 @@ struct mailbox::message : public slab_allocated { uint64_t tag; - uint64_t badge; + uint64_t subtag; uint16_t reply_tag; - - uint16_t reserved0; - uint16_t reserved1; - uint8_t handle_count; - uint8_t data_len; - handle handles[mailbox::max_handle_count]; - uint8_t data[mailbox::max_data_length]; + j6_handle_t handles[mailbox::max_handle_count]; }; class mailbox::replyer diff --git a/src/kernel/objects/process.cpp b/src/kernel/objects/process.cpp index 31aa45a..03d4a39 100644 --- a/src/kernel/objects/process.cpp +++ b/src/kernel/objects/process.cpp @@ -1,6 +1,7 @@ #include #include "assert.h" +#include "capabilities.h" #include "cpu.h" #include "objects/process.h" #include "objects/thread.h" @@ -19,17 +20,16 @@ namespace obj { process::process() : kobject {kobject::type::process}, - m_next_handle {1}, m_state {state::running} { - m_self_handle = add_handle(this, process::self_caps); + m_self_handle = g_cap_table.create(this, process::self_caps); + add_handle(m_self_handle); } // The "kernel process"-only constructor process::process(page_table *kpml4) : kobject {kobject::type::process}, m_space {kpml4}, - m_next_handle {self_handle()+1}, m_state {state::running} { } @@ -121,51 +121,40 @@ process::thread_exited(thread *th) return false; } -j6_handle_t -process::add_handle(kobject *obj, j6_cap_t caps) +void +process::add_handle(j6_handle_t handle) { - if (!obj) - return j6_handle_invalid; - - handle h {m_next_handle++, obj, caps}; - j6_handle_t id = h.id; - - m_handles.insert(id, h); - return id; -} - -j6_handle_t -process::add_handle(const handle &hnd) -{ - if (!hnd.object || hnd.id == j6_handle_invalid) - return j6_handle_invalid; - - handle h {m_next_handle++, hnd.object, hnd.caps()}; - j6_handle_t id = h.id; - - m_handles.insert(id, h); - return id; + m_handles.add(handle); } bool process::remove_handle(j6_handle_t id) { - return m_handles.erase(id); + return m_handles.remove(id); } -handle * -process::lookup_handle(j6_handle_t id) +bool +process::has_handle(j6_handle_t id) { - return m_handles.find(id); + return m_handles.contains(id); } size_t -process::list_handles(j6_handle_t *handles, size_t len) +process::list_handles(j6_handle_descriptor *handles, size_t len) { - for (const auto &i : m_handles) { - if (len-- == 0) - break; - *handles++ = i.key; + size_t count = 0; + for (j6_handle_t handle : m_handles) { + + capability *cap = g_cap_table.find(handle); + kassert(cap, "Found process handle that wasn't in the cap table"); + if (!cap) continue; + + j6_handle_descriptor &desc = handles[count]; + desc.handle = handle; + desc.caps = cap->caps; + desc.type = static_cast(cap->type); + + if (++count == len) break; } return m_handles.count(); diff --git a/src/kernel/objects/process.h b/src/kernel/objects/process.h index 98dff9e..8f30a3b 100644 --- a/src/kernel/objects/process.h +++ b/src/kernel/objects/process.h @@ -4,9 +4,10 @@ #include #include +#include #include -#include "objects/handle.h" +#include "heap_allocator.h" #include "objects/kobject.h" #include "page_table.h" #include "vm_space.h" @@ -59,32 +60,25 @@ public: /// \returns The newly created thread object thread * create_thread(uintptr_t rsp3 = 0, uint8_t priorty = default_priority); - /// Start tracking an object with a handle. - /// \args obj The object this handle refers to - /// \args caps The capabilities on this handle - /// \returns The new handle id for this object - j6_handle_t add_handle(kobject *obj, j6_cap_t caps); + /// Give this process access to an object capability handle + /// \args handle A handle to give this process access to + void add_handle(j6_handle_t handle); - /// Start tracking an object with a handle. - /// \args hnd An existing handle to copy into this process - /// \returns The new handle id for this object - j6_handle_t add_handle(const handle &hnd); - - /// Stop tracking an object with a handle. + /// Remove access to an object capability from this process /// \args handle The handle that refers to the object /// \returns True if the handle was removed bool remove_handle(j6_handle_t handle); - /// Lookup an object for a handle - /// \args handle The handle to the object - /// \returns Pointer to the handle struct, or null if not found - handle * lookup_handle(j6_handle_t handle); + /// Return whether this process has access to the given object capability + /// \args handle The handle to the capability + /// \returns True if the process has been given access to that capability + bool has_handle(j6_handle_t handle); /// Get the list of handle ids this process owns - /// \arg handles Pointer to an array of handles to copy into + /// \arg handles Pointer to an array of handles descriptors to copy into /// \arg len Size of the array /// \returns Total number of handles (may be more than number copied) - size_t list_handles(j6_handle_t *handles, size_t len); + size_t list_handles(j6_handle_descriptor *handles, size_t len); /// Inform the process of an exited thread /// \args th The thread which has exited @@ -119,8 +113,7 @@ private: util::vector m_threads; - j6_handle_t m_next_handle; - util::map m_handles; + util::node_set m_handles; enum class state : uint8_t { running, exited }; state m_state; diff --git a/src/kernel/objects/thread.cpp b/src/kernel/objects/thread.cpp index 62e1c40..56001eb 100644 --- a/src/kernel/objects/thread.cpp +++ b/src/kernel/objects/thread.cpp @@ -1,5 +1,6 @@ #include +#include "capabilities.h" #include "cpu.h" #include "logger.h" #include "memory.h" @@ -31,7 +32,8 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) : m_tcb.rsp0 = rsp0; m_creator = current_cpu().thread; - m_self_handle = parent.add_handle(this, thread::parent_caps); + m_self_handle = g_cap_table.create(this, thread::parent_caps); + parent.add_handle(m_self_handle); } thread::~thread() diff --git a/src/kernel/syscall_verify.cpp.cog b/src/kernel/syscall_verify.cpp.cog index 040e92f..14cda18 100644 --- a/src/kernel/syscall_verify.cpp.cog +++ b/src/kernel/syscall_verify.cpp.cog @@ -87,10 +87,10 @@ for id, scope, method in syscalls.methods: else: name = f"{method.name}" - args = [] - argdefs = [] - cxxargdefs = [] - refparams = [] + args = [] # The function call args to call the impl + argdefs = [] # The user-facing syscall args signature + cxxargdefs = [] # The kernel syscall impl args signature + refparams = [] # The list of params which are kobjects handles = [] objparams = [] @@ -105,8 +105,7 @@ for id, scope, method in syscalls.methods: argdefs.append(("j6_handle_t", "self")) if "handle" in method.options: - args.append("self_handle") - cxxargdefs.append(f"obj::handle *self_handle") + args.append("self") else: args.append("self_obj") cxxargdefs.append(f"obj::{scope.cname} *self") @@ -131,13 +130,10 @@ for id, scope, method in syscalls.methods: objparams.append((type, arg)) args.append(f"{arg}_obj") cxxargdefs.append(f"{type} {arg}") - else: - args.append(f"{arg}_handle") - cxxargdefs.append(f"obj::handle *{arg}_handle") - break - else: - cxxargdefs.append(f"{type} {arg}") - args.append(arg) + break + + cxxargdefs.append(f"{type} {arg}") + args.append(arg) if not needs_handle and param.caps: handles.append(( @@ -174,21 +170,17 @@ for id, scope, method in syscalls.methods: cog.outl( " return j6_err_invalid_arg;") cog.outl() + if handles: + cog.outl(f" j6_status_t res;") + for type, arg, caps in handles: - cog.outl(f" obj::handle *{arg}_handle = get_handle({arg});") - cog.outl(f" if (!{arg}_handle) return j6_err_invalid_arg;") - + capsval = "0" if caps: - allcaps = " | ".join(caps) - cog.outl(f" j6_cap_t {arg}_caps_req = {allcaps};") - cog.outl(f" if (!{arg}_handle->has_cap({arg}_caps_req)) return j6_err_denied;") + capsval = " | ".join(caps) - for type, arg in objparams: - if type.endswith('*'): - type = type[:-1].strip() - - cog.outl(f" {type} *{arg}_obj = {arg}_handle->as();") - cog.outl(f" if (!{arg}_obj) return j6_err_invalid_arg;") + cog.outl(f" obj::{type} *{arg}_obj = nullptr;") + cog.outl(f" res = get_handle({arg}, {capsval}, {arg}_obj);") + cog.outl(f" if (res != j6_status_ok) return res;") cog.outl() if "noreturn" in method.options: diff --git a/src/kernel/syscalls/handle.cpp b/src/kernel/syscalls/handle.cpp index 6d613f4..bbb1a11 100644 --- a/src/kernel/syscalls/handle.cpp +++ b/src/kernel/syscalls/handle.cpp @@ -9,7 +9,7 @@ using namespace obj; namespace syscalls { j6_status_t -handle_list(j6_handle_t *handles, size_t *handles_len) +handle_list(j6_handle_descriptor *handles, size_t *handles_len) { process &p = process::current(); size_t requested = *handles_len; @@ -23,12 +23,11 @@ handle_list(j6_handle_t *handles, size_t *handles_len) } j6_status_t -handle_clone(handle *orig, j6_handle_t *clone, uint32_t mask) +handle_clone(j6_handle_t orig, j6_handle_t *clone, uint32_t mask) { + *clone = g_cap_table.derive(orig, mask); process &p = process::current(); - *clone = p.add_handle( - orig->object, - orig->caps() & mask); + p.add_handle(*clone); return j6_status_ok; } diff --git a/src/kernel/syscalls/helpers.h b/src/kernel/syscalls/helpers.h index 4b67e00..410ab53 100644 --- a/src/kernel/syscalls/helpers.h +++ b/src/kernel/syscalls/helpers.h @@ -4,6 +4,7 @@ #include +#include "capabilities.h" #include "objects/kobject.h" #include "objects/process.h" @@ -12,41 +13,43 @@ namespace syscalls { template T * construct_handle(j6_handle_t *id, Args... args) { - obj::process &p = obj::process::current(); T *o = new T {args...}; - *id = p.add_handle(o, T::creation_caps); + *id = g_cap_table.create(o, T::creation_caps); + + obj::process &p = obj::process::current(); + p.add_handle(*id); + return o; } template -obj::handle * get_handle(j6_handle_t id) +j6_status_t get_handle(j6_handle_t id, j6_cap_t caps, T *&object) { + capability *capdata = g_cap_table.find(id); + if (!capdata || capdata->type != T::type) + return j6_err_invalid_arg; + obj::process &p = obj::process::current(); - obj::handle *h = p.lookup_handle(id); - if (!h || h->type() != T::type) - return nullptr; - return h; + if (!p.has_handle(id) || (capdata->caps & caps) != caps) + return j6_err_denied; + + object = static_cast(capdata->object); + return j6_status_ok; } template <> -inline obj::handle * get_handle(j6_handle_t id) +inline j6_status_t get_handle(j6_handle_t id, j6_cap_t caps, obj::kobject *&object) { + capability *capdata = g_cap_table.find(id); + if (!capdata) + return j6_err_invalid_arg; + obj::process &p = obj::process::current(); - return p.lookup_handle(id); + if (!p.has_handle(id) || (capdata->caps & caps) != caps) + return j6_err_denied; + + object = capdata->object; + return j6_status_ok; } -template -T * remove_handle(j6_handle_t id) -{ - obj::handle *h = get_handle(id); - T *o = nullptr; - - if (h) { - o = h->object; - obj::process &p = obj::process::current(); - p.remove_handle(id); - } - return o; -} - -} +} // namespace syscalls diff --git a/src/kernel/syscalls/mailbox.cpp b/src/kernel/syscalls/mailbox.cpp index 30c172e..a367f94 100644 --- a/src/kernel/syscalls/mailbox.cpp +++ b/src/kernel/syscalls/mailbox.cpp @@ -31,30 +31,20 @@ j6_status_t prep_send( mailbox::message *msg, uint64_t tag, - uint64_t badge, - const void *data, - size_t data_len, + uint64_t subtag, const j6_handle_t *handles, size_t handle_count) { if (!msg || - data_len > mailbox::max_data_length || handle_count > mailbox::max_handle_count) return j6_err_invalid_arg; msg->tag = tag; - msg->badge = badge; + msg->subtag = subtag; msg->handle_count = handle_count; - for (unsigned i = 0; i < handle_count; ++i) { - handle const *h = get_handle(handles[i]); - if (!h) - return j6_err_invalid_arg; - msg->handles[i] = *h; - } + memcpy(msg->handles, handles, sizeof(j6_handle_t) * handle_count); - msg->data_len = data_len; - memcpy(msg->data, data, data_len); return j6_status_ok; } @@ -62,43 +52,35 @@ void prep_receive( mailbox::message *msg, uint64_t *tag, - uint64_t *badge, + uint64_t *subtag, uint16_t *reply_tag, - void *data, - size_t *data_len, j6_handle_t *handles, size_t *handle_count) { if (tag) *tag = msg->tag; - if (badge) *badge = msg->badge; + if (subtag) *subtag = msg->subtag; if (reply_tag) *reply_tag = msg->reply_tag; - *data_len = msg->data_len; - memcpy(data, msg->data, msg->data_len); - *handle_count = msg->handle_count; process &proc = process::current(); for (size_t i = 0; i < msg->handle_count; ++i) { - handles[i] = proc.add_handle(msg->handles[i]); - msg->handles[i] = {}; + proc.add_handle(msg->handles[i]); + handles[i] = msg->handles[i]; } } j6_status_t mailbox_send( - handle *self_handle, + mailbox *self, uint64_t tag, - const void * data, - size_t data_len, + uint64_t subtag, j6_handle_t * handles, size_t handle_count) { - mailbox *self = self_handle->as(); mailbox::message *msg = new mailbox::message; j6_status_t s = prep_send(msg, - tag, self_handle->badge, - data, data_len, + tag, subtag, handles, handle_count); if (s != j6_status_ok) { @@ -114,17 +96,14 @@ mailbox_send( j6_status_t mailbox_receive( mailbox *self, - uint64_t * tag, - void * data, - size_t * data_len, - j6_handle_t * handles, - size_t * handle_count, - uint16_t * reply_tag, - uint64_t * badge, + uint64_t *tag, + uint64_t *subtag, + j6_handle_t *handles, + size_t *handle_count, + uint16_t *reply_tag, uint64_t flags) { - if (*data_len < mailbox::max_data_length || - *handle_count < mailbox::max_handle_count) + if (*handle_count < mailbox::max_handle_count) return j6_err_insufficient; mailbox::message *msg = nullptr; @@ -138,8 +117,7 @@ mailbox_receive( } prep_receive(msg, - tag, badge, reply_tag, - data, data_len, + tag, subtag, reply_tag, handles, handle_count); if (*reply_tag == 0) @@ -150,19 +128,16 @@ mailbox_receive( j6_status_t mailbox_call( - handle *self_handle, - uint64_t * tag, - void * data, - size_t * data_len, - j6_handle_t * handles, - size_t * handle_count) + mailbox *self, + uint64_t *tag, + uint64_t *subtag, + j6_handle_t *handles, + size_t *handle_count) { - mailbox *self = self_handle->as(); mailbox::message *msg = new mailbox::message; j6_status_t s = prep_send(msg, - *tag, self_handle->badge, - data, *data_len, + *tag, *subtag, handles, *handle_count); if (s != j6_status_ok) { @@ -177,8 +152,7 @@ mailbox_call( } prep_receive(msg, - tag, nullptr, nullptr, - data, data_len, + tag, subtag, 0, handles, handle_count); delete msg; @@ -190,8 +164,7 @@ j6_status_t mailbox_respond( mailbox *self, uint64_t tag, - const void * data, - size_t data_len, + uint64_t subtag, j6_handle_t * handles, size_t handle_count, uint16_t reply_tag) @@ -200,8 +173,7 @@ mailbox_respond( if (!reply.valid()) return j6_err_invalid_arg; - j6_status_t s = prep_send(reply.msg, tag, 0, - data, data_len, + j6_status_t s = prep_send(reply.msg, tag, subtag, handles, handle_count); if (s != j6_status_ok) { @@ -216,22 +188,19 @@ mailbox_respond( j6_status_t mailbox_respond_receive( mailbox *self, - uint64_t * tag, - void * data, - size_t * data_len, - size_t data_in, - j6_handle_t * handles, - size_t * handle_count, + uint64_t *tag, + uint64_t *subtag, + j6_handle_t *handles, + size_t *handle_count, size_t handles_in, - uint16_t * reply_tag, - uint64_t * badge, + uint16_t *reply_tag, uint64_t flags) { - j6_status_t s = mailbox_respond(self, *tag, data, data_in, handles, handles_in, *reply_tag); + j6_status_t s = mailbox_respond(self, *tag, *subtag, handles, handles_in, *reply_tag); if (s != j6_status_ok) return s; - s = mailbox_receive(self, tag, data, data_len, handles, handle_count, reply_tag, badge, flags); + s = mailbox_receive(self, tag, subtag, handles, handle_count, reply_tag, flags); if (s != j6_status_ok) return s; diff --git a/src/kernel/syscalls/process.cpp b/src/kernel/syscalls/process.cpp index c3bfb17..5157f74 100644 --- a/src/kernel/syscalls/process.cpp +++ b/src/kernel/syscalls/process.cpp @@ -41,12 +41,9 @@ process_exit(int32_t status) } j6_status_t -process_give_handle(process *self, handle *target, j6_handle_t *received) +process_give_handle(process *self, j6_handle_t target) { - j6_handle_t out = self->add_handle(target->object, target->caps()); - if (received) - *received = out; - + self->add_handle(target); return j6_status_ok; } diff --git a/src/libraries/j6/init.cpp b/src/libraries/j6/init.cpp index 65e671e..968076f 100644 --- a/src/libraries/j6/init.cpp +++ b/src/libraries/j6/init.cpp @@ -12,26 +12,26 @@ j6_handle_t __handle_self; namespace { - constexpr size_t static_arr_size = 8; - j6_handle_t handle_array[static_arr_size]; + constexpr size_t static_arr_count = 8; + j6_handle_descriptor handle_array[static_arr_count]; } // namespace j6_handle_t j6_find_first_handle(j6_object_type obj_type) { - size_t count = static_arr_size; - j6_handle_t *handles = handle_array; + size_t count = static_arr_count; + j6_handle_descriptor *handles = handle_array; j6_status_t s = j6_handle_list(handles, &count); if (s != j6_err_insufficient && s != j6_status_ok) return j6_handle_invalid; - if (count > static_arr_size) - count = static_arr_size; + if (count > static_arr_count) + count = static_arr_count; for (size_t i = 0; i < count; ++i) { - uint8_t type = (handles[i] >> 56); - if (type == obj_type) return handles[i]; + j6_handle_descriptor &desc = handle_array[i]; + if (desc.type == obj_type) return desc.handle; } return j6_handle_invalid; diff --git a/src/libraries/j6/j6/types.h b/src/libraries/j6/j6/types.h index a556883..b1f858b 100644 --- a/src/libraries/j6/j6/types.h +++ b/src/libraries/j6/j6/types.h @@ -27,15 +27,12 @@ typedef uint64_t j6_tag_t; #define j6_tag_from_irq(x) ((x) | j6_tag_irq_base) #define j6_tag_to_irq(x) ((x) & ~j6_tag_irq_base) -/// Handles are references and capabilities to other objects. A handle is -/// an id in the lower 32 bits, a bitfield of capabilities in bits 32-55 -/// and a type id in bits 56-63. +/// Handles are references and capabilities to other objects. typedef uint64_t j6_handle_t; +#define j6_handle_invalid 0 /// Bitfield for storage of capabilities on their own -typedef uint32_t j6_cap_t; - -#define j6_handle_invalid ((j6_handle_t)-1) +typedef uint16_t j6_cap_t; enum j6_object_type { #define OBJECT_TYPE( name, val ) j6_object_type_ ## name = val, @@ -44,3 +41,12 @@ enum j6_object_type { j6_object_type_max }; + +/// Description of a handle +struct j6_handle_descriptor +{ + j6_handle_t handle; + j6_cap_t caps; + j6_object_type type; +}; + diff --git a/src/user/drv.uart/main.cpp b/src/user/drv.uart/main.cpp index 29d09b3..51322a0 100644 --- a/src/user/drv.uart/main.cpp +++ b/src/user/drv.uart/main.cpp @@ -60,16 +60,15 @@ channel_pump_loop() return 3; uint64_t tag = j6_proto_sl_register; - uint64_t data = "jsix.protocol.stream.ouput"_id; - size_t data_len = sizeof(data); + uint64_t proto_id = "jsix.protocol.stream.ouput"_id; size_t handle_count = 1; - result = j6_mailbox_call(slp, &tag, - &data, &data_len, + result = j6_mailbox_call(slp, + &tag, &proto_id, &cout_write, &handle_count); if (result != j6_status_ok) return 4; - if (tag != j6_proto_base_status || data != j6_status_ok) + if (tag != j6_proto_base_status) return 5; result = j6_system_request_iopl(g_handle_sys, 3); diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index ac6f8f4..8bc773a 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -57,13 +57,13 @@ load_program( return false; } - res = j6_process_give_handle(proc, sys, nullptr); + res = j6_process_give_handle(proc, sys); if (res != j6_status_ok) { sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", prog.filename, res); return false; } - res = j6_process_give_handle(proc, slp, nullptr); + res = j6_process_give_handle(proc, slp); if (res != j6_status_ok) { sprintf(err_msg, " ** error loading program '%s': giving SLP handle: %lx", prog.filename, res); return false; diff --git a/src/user/srv.init/service_locator.cpp b/src/user/srv.init/service_locator.cpp index 7b61814..60cf67d 100644 --- a/src/user/srv.init/service_locator.cpp +++ b/src/user/srv.init/service_locator.cpp @@ -5,71 +5,72 @@ #include #include #include -#include +#include #include "service_locator.h" +struct handle_entry +{ + uint64_t protocol; + j6_handle_t handle; +}; + +uint64_t & get_map_key(handle_entry &e) { return e.protocol; } + void service_locator_start(j6_handle_t mb) { // TODO: This should be a multimap - util::map services; + util::node_map services; uint64_t tag; + uint64_t subtag; uint16_t reply_tag; - uint8_t data[100]; - size_t data_len = sizeof(data); - j6_handle_t handles[10]; size_t handles_count = sizeof(handles)/sizeof(j6_handle_t); - j6_status_t s = j6_mailbox_receive(mb, &tag, - data, &data_len, + j6_status_t s = j6_mailbox_receive(mb, + &tag, &subtag, handles, &handles_count, - &reply_tag, nullptr, + &reply_tag, j6_mailbox_block); uint64_t proto_id; - uint64_t *data_words = reinterpret_cast(data); while (true) { - j6_handle_t *found = nullptr; + handle_entry *found = nullptr; switch (tag) { case j6_proto_base_get_proto_id: tag = j6_proto_base_proto_id; - *data_words = j6_proto_sl_id; - data_len = sizeof(j6_status_t); + subtag = j6_proto_sl_id; handles_count = 0; break; case j6_proto_sl_register: - proto_id = *data_words; + proto_id = subtag; if (handles_count != 1) { tag = j6_proto_base_status; - *data_words = j6_err_invalid_arg; - data_len = sizeof(j6_status_t); + subtag = j6_err_invalid_arg; handles_count = 0; break; } - services.insert( proto_id, handles[0] ); + services.insert( {proto_id, handles[0]} ); tag = j6_proto_base_status; - *data_words = j6_status_ok; - data_len = sizeof(j6_status_t); + subtag = j6_status_ok; handles_count = 0; break; case j6_proto_sl_find: - proto_id = *data_words; + proto_id = subtag; tag = j6_proto_sl_result; - data_len = 0; found = services.find(proto_id); if (found) { handles_count = 1; - handles[0] = *found; + handles[0] = found->handle; } else { handles_count = 0; } @@ -77,21 +78,18 @@ service_locator_start(j6_handle_t mb) default: tag = j6_proto_base_status; - *data_words = j6_err_invalid_arg; - data_len = sizeof(j6_status_t); + subtag = j6_err_invalid_arg; handles_count = 0; break; } - size_t data_in = data_len; size_t handles_in = handles_count; - data_len = sizeof(data); handles_count = sizeof(handles)/sizeof(j6_handle_t); - s = j6_mailbox_respond_receive(mb, &tag, - data, &data_len, data_in, + s = j6_mailbox_respond_receive(mb, + &tag, &subtag, handles, &handles_count, handles_in, - &reply_tag, nullptr, + &reply_tag, j6_mailbox_block); } } diff --git a/src/user/srv.logger/main.cpp b/src/user/srv.logger/main.cpp index c7520fd..96bfe5f 100644 --- a/src/user/srv.logger/main.cpp +++ b/src/user/srv.logger/main.cpp @@ -111,7 +111,6 @@ main(int argc, const char **argv) { j6_log("logging server starting"); - j6_status_t result = j6_status_ok; g_handle_sys = j6_find_first_handle(j6_object_type_system); if (g_handle_sys == j6_handle_invalid) @@ -123,22 +122,20 @@ main(int argc, const char **argv) j6_handle_t cout = j6_handle_invalid; - for (unsigned i = 0; i < 5; ++i) { + for (unsigned i = 0; i < 100; ++i) { uint64_t tag = j6_proto_sl_find; uint64_t proto_id = "jsix.protocol.stream.ouput"_id; - size_t data_len = sizeof(proto_id); size_t handle_count = 0; - result = j6_mailbox_call(slp, &tag, - &proto_id, &data_len, - &cout, &handle_count); - if (result == j6_status_ok && + j6_status_t s = j6_mailbox_call(slp, &tag, + &proto_id, &cout, &handle_count); + if (s == j6_status_ok && tag == j6_proto_sl_result && handle_count == 1) break; cout = j6_handle_invalid; - j6_thread_sleep(1000); // 1ms + j6_thread_sleep(10000); // 10ms } if (cout == j6_handle_invalid) diff --git a/src/user/test_runner/tests/mailbox.cpp b/src/user/test_runner/tests/mailbox.cpp index afb20ec..634caa4 100644 --- a/src/user/test_runner/tests/mailbox.cpp +++ b/src/user/test_runner/tests/mailbox.cpp @@ -24,19 +24,16 @@ TEST_CASE( mailbox_tests, would_block ) CHECK( s == j6_status_ok, "Could not create a mailbox" ); uint64_t tag = 12345; - uint8_t buffer[128]; - size_t buffer_size = 128; + uint64_t subtag = 67890; j6_handle_t handles[10]; size_t handle_count = 10; uint16_t reply_tag = 0; - uint64_t badge = 0; uint64_t flags = 0; - s = j6_mailbox_receive( mb, &tag, - buffer, &buffer_size, + s = j6_mailbox_receive( mb, + &tag, &subtag, handles, &handle_count, - &reply_tag, &badge, - flags ); + &reply_tag, flags ); CHECK( s == j6_status_would_block, "Should have gotten would block error" ); j6_mailbox_close(mb); @@ -51,37 +48,29 @@ TEST_CASE( mailbox_tests, send_receive ) CHECK( s == j6_status_ok, "Could not create a mailbox" ); uint64_t out_tag = 12345; - uint8_t out_buffer[128] = {2, 4, 6, 8, 10, 12, 14}; - size_t out_buffer_size = 7; + uint64_t out_subtag = 67890; j6_handle_t out_handles[10]; size_t out_handle_count = 0; - s = j6_mailbox_send( mb, out_tag, - out_buffer, out_buffer_size, + s = j6_mailbox_send( mb, out_tag, out_subtag, out_handles, out_handle_count ); CHECK( s == j6_status_ok, "Did not send successfully" ); uint64_t in_tag = 0; - uint8_t in_buffer[128]; - size_t in_buffer_size = 128; + uint64_t in_subtag = 0; j6_handle_t in_handles[10]; size_t in_handle_count = 10; uint16_t in_reply_tag = 0; - uint64_t in_badge = 0; uint64_t in_flags = 0; - s = j6_mailbox_receive( mb, &in_tag, - in_buffer, &in_buffer_size, + s = j6_mailbox_receive( mb, &in_tag, &in_subtag, in_handles, &in_handle_count, - &in_reply_tag, &in_badge, - in_flags ); + &in_reply_tag, in_flags ); CHECK( s == j6_status_ok, "Did not receive successfully" ); CHECK_BARE( in_tag == out_tag ); - CHECK_BARE( in_buffer_size == out_buffer_size ); + CHECK_BARE( in_subtag == out_subtag ); CHECK_BARE( in_handle_count == out_handle_count ); - CHECK_BARE( memcmp(out_buffer, in_buffer, in_buffer_size) == 0 ); - j6_mailbox_close(mb); }