mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[kernel] Make capabilities/handles global
Instead of handles / capabilities having numeric ids that are only valid for the owning process, they are now global in a system capabilities table. This will allow for specifying capabilities in IPC that doesn't need to be kernel-controlled. Processes will still need to be granted access to given capabilities, but that can become a simpler system call than the current method of sending them through mailbox messages (and worse, having to translate every one into a new capability like was the case before). In order to track which handles a process has access to, a new node_set based on node_map allows for an efficient storage and lookup of handles.
This commit is contained in:
@@ -1,99 +0,0 @@
|
||||
#pragma once
|
||||
/// \file handle.h
|
||||
/// Definition of kobject handles
|
||||
|
||||
#include <j6/types.h>
|
||||
#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<j6_handle_t>(caps) << cap_shift) & cap_mask) |
|
||||
static_cast<j6_handle_t>(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<kobject::type>(id >> 56);
|
||||
}
|
||||
|
||||
inline int compare(const handle &o) {
|
||||
return id > o.id ? 1 : id < o.id ? -1 : 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T * as() {
|
||||
if (type() != T::type) return nullptr;
|
||||
return reinterpret_cast<T*>(object);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const T * as() const {
|
||||
if (type() != T::type) return nullptr;
|
||||
return reinterpret_cast<const T*>(object);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline kobject * as<kobject>() { return object; }
|
||||
|
||||
template <>
|
||||
inline const kobject * as<kobject>() const { return object; }
|
||||
|
||||
j6_handle_t id;
|
||||
uint64_t badge;
|
||||
kobject *object;
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <util/counted.h>
|
||||
|
||||
#include "objects/handle.h"
|
||||
#include "objects/mailbox.h"
|
||||
#include "objects/thread.h"
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <util/map.h>
|
||||
#include <util/spinlock.h>
|
||||
|
||||
#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<message, 1>
|
||||
{
|
||||
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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <util/no_construct.h>
|
||||
|
||||
#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<j6_object_type>(cap->type);
|
||||
|
||||
if (++count == len) break;
|
||||
}
|
||||
|
||||
return m_handles.count();
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <j6/cap_flags.h>
|
||||
#include <util/map.h>
|
||||
#include <util/node_map.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
#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<thread*> m_threads;
|
||||
|
||||
j6_handle_t m_next_handle;
|
||||
util::map<j6_handle_t, handle> m_handles;
|
||||
util::node_set<j6_handle_t, j6_handle_invalid, heap_allocated> m_handles;
|
||||
|
||||
enum class state : uint8_t { running, exited };
|
||||
state m_state;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <util/pointers.h>
|
||||
|
||||
#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()
|
||||
|
||||
Reference in New Issue
Block a user