mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04: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:
@@ -13,6 +13,12 @@
|
|||||||
- name: heap
|
- name: heap
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
|
- name: capsmap
|
||||||
|
size: 32G
|
||||||
|
|
||||||
|
- name: caps
|
||||||
|
size: 32G
|
||||||
|
|
||||||
- name: stacks
|
- name: stacks
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ object mailbox : object {
|
|||||||
method close [destructor cap:close]
|
method close [destructor cap:close]
|
||||||
|
|
||||||
# Asynchronously send a message to the reciever
|
# Asynchronously send a message to the reciever
|
||||||
method send [cap:send handle] {
|
method send [cap:send] {
|
||||||
param tag uint64
|
param tag uint64
|
||||||
param data buffer [zero_ok]
|
param subtag uint64
|
||||||
param handles ref object [list]
|
param handles ref object [list]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,19 +24,18 @@ object mailbox : object {
|
|||||||
# arrive if block is true.
|
# arrive if block is true.
|
||||||
method receive [cap:receive] {
|
method receive [cap:receive] {
|
||||||
param tag uint64 [out]
|
param tag uint64 [out]
|
||||||
param data buffer [out zero_ok]
|
param subtag uint64 [out]
|
||||||
param handles ref object [out list zero_ok]
|
param handles ref object [out list zero_ok]
|
||||||
param reply_tag uint16 [out optional]
|
param reply_tag uint16 [out optional]
|
||||||
param badge uint64 [out optional]
|
|
||||||
param flags uint64
|
param flags uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
# Send a message to the reciever, and block until a
|
# Send a message to the reciever, and block until a
|
||||||
# response is sent. Note that getting this response
|
# response is sent. Note that getting this response
|
||||||
# does not require the receive capability.
|
# does not require the receive capability.
|
||||||
method call [cap:send handle] {
|
method call [cap:send] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param data buffer [inout zero_ok]
|
param subtag uint64 [inout]
|
||||||
param handles ref object [inout list zero_ok]
|
param handles ref object [inout list zero_ok]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +43,7 @@ object mailbox : object {
|
|||||||
# requires the receive capability and not the send capability.
|
# requires the receive capability and not the send capability.
|
||||||
method respond [cap:receive] {
|
method respond [cap:receive] {
|
||||||
param tag uint64
|
param tag uint64
|
||||||
param data buffer [zero_ok]
|
param subtag uint64
|
||||||
param handles ref object [list zero_ok]
|
param handles ref object [list zero_ok]
|
||||||
param reply_tag uint16
|
param reply_tag uint16
|
||||||
}
|
}
|
||||||
@@ -54,12 +53,10 @@ object mailbox : object {
|
|||||||
# capability.
|
# capability.
|
||||||
method respond_receive [cap:receive] {
|
method respond_receive [cap:receive] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param data buffer [inout zero_ok]
|
param subtag uint64 [inout]
|
||||||
param data_in size
|
|
||||||
param handles ref object [inout list zero_ok]
|
param handles ref object [inout list zero_ok]
|
||||||
param handles_in size
|
param handles_in size
|
||||||
param reply_tag uint16 [inout]
|
param reply_tag uint16 [inout]
|
||||||
param badge uint64 [out optional]
|
|
||||||
param flags uint64
|
param flags uint64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,5 @@ object process : object {
|
|||||||
# object as the specified handle.
|
# object as the specified handle.
|
||||||
method give_handle {
|
method give_handle {
|
||||||
param target ref object [handle] # A handle in the caller process to send
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ interface syscalls [syscall] {
|
|||||||
# supplied list is not big enough, will set the size
|
# supplied list is not big enough, will set the size
|
||||||
# needed in `size` and return j6_err_insufficient
|
# needed in `size` and return j6_err_insufficient
|
||||||
function handle_list {
|
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
|
# Create a clone of an existing handle, possibly with
|
||||||
|
|||||||
62
src/kernel/capabilities.cpp
Normal file
62
src/kernel/capabilities.cpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include <util/hash.h>
|
||||||
|
|
||||||
|
#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<capability*>(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);
|
||||||
|
}
|
||||||
48
src/kernel/capabilities.h
Normal file
48
src/kernel/capabilities.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file capabilities.h
|
||||||
|
/// Capability table definitions
|
||||||
|
|
||||||
|
#include <j6/types.h>
|
||||||
|
#include <util/node_map.h>
|
||||||
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
|
#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<j6_handle_t, capability, j6_handle_invalid>;
|
||||||
|
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; }
|
||||||
@@ -11,6 +11,7 @@ kernel = module("kernel",
|
|||||||
"apic.cpp",
|
"apic.cpp",
|
||||||
"assert.cpp",
|
"assert.cpp",
|
||||||
"boot.s",
|
"boot.s",
|
||||||
|
"capabilities.cpp",
|
||||||
"clock.cpp",
|
"clock.cpp",
|
||||||
"cpprt.cpp",
|
"cpprt.cpp",
|
||||||
"cpu.cpp",
|
"cpu.cpp",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "capabilities.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
@@ -86,7 +87,10 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
|
|||||||
using obj::vm_flags;
|
using obj::vm_flags;
|
||||||
|
|
||||||
obj::process *p = new obj::process;
|
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();
|
vm_space &space = p->space();
|
||||||
for (const auto § : program.sections) {
|
for (const auto § : program.sections) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "capabilities.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
#include "heap_allocator.h"
|
#include "heap_allocator.h"
|
||||||
@@ -31,6 +32,9 @@ uintptr_t g_slabs_bump_pointer;
|
|||||||
static util::no_construct<heap_allocator> __g_kernel_heap_storage;
|
static util::no_construct<heap_allocator> __g_kernel_heap_storage;
|
||||||
heap_allocator &g_kernel_heap = __g_kernel_heap_storage.value;
|
heap_allocator &g_kernel_heap = __g_kernel_heap_storage.value;
|
||||||
|
|
||||||
|
static util::no_construct<cap_table> __g_cap_table_storage;
|
||||||
|
cap_table &g_cap_table = __g_cap_table_storage.value;
|
||||||
|
|
||||||
static util::no_construct<frame_allocator> __g_frame_allocator_storage;
|
static util::no_construct<frame_allocator> __g_frame_allocator_storage;
|
||||||
frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value;
|
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<obj::vm_area_untracked> __g_kernel_heapmap_area_storage;
|
static util::no_construct<obj::vm_area_untracked> __g_kernel_heapmap_area_storage;
|
||||||
obj::vm_area_untracked &g_kernel_heapmap_area = __g_kernel_heapmap_area_storage.value;
|
obj::vm_area_untracked &g_kernel_heapmap_area = __g_kernel_heapmap_area_storage.value;
|
||||||
|
|
||||||
|
static util::no_construct<obj::vm_area_untracked> __g_cap_table_area_storage;
|
||||||
|
obj::vm_area_untracked &g_cap_table_area = __g_cap_table_area_storage.value;
|
||||||
|
|
||||||
static util::no_construct<obj::vm_area_guarded> __g_kernel_stacks_storage;
|
static util::no_construct<obj::vm_area_guarded> __g_kernel_stacks_storage;
|
||||||
obj::vm_area_guarded &g_kernel_stacks = __g_kernel_stacks_storage.value;
|
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};
|
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 {
|
obj::vm_area *stacks = new (&g_kernel_stacks) obj::vm_area_guarded {
|
||||||
mem::stacks_offset,
|
mem::stacks_offset,
|
||||||
mem::kernel_stack_pages,
|
mem::kernel_stack_pages,
|
||||||
|
|||||||
@@ -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 <util/counted.h>
|
||||||
|
|
||||||
#include "objects/handle.h"
|
|
||||||
#include "objects/mailbox.h"
|
#include "objects/mailbox.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <util/map.h>
|
#include <util/map.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
#include "objects/handle.h"
|
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
#include "slab_allocated.h"
|
#include "slab_allocated.h"
|
||||||
#include "wait_queue.h"
|
#include "wait_queue.h"
|
||||||
@@ -26,11 +25,8 @@ public:
|
|||||||
|
|
||||||
static constexpr kobject::type type = kobject::type::mailbox;
|
static constexpr kobject::type type = kobject::type::mailbox;
|
||||||
|
|
||||||
/// Max message data length
|
|
||||||
constexpr static size_t max_data_length = 88;
|
|
||||||
|
|
||||||
/// Max message handle count
|
/// Max message handle count
|
||||||
constexpr static size_t max_handle_count = 6;
|
constexpr static size_t max_handle_count = 5;
|
||||||
|
|
||||||
struct message;
|
struct message;
|
||||||
|
|
||||||
@@ -91,18 +87,12 @@ struct mailbox::message :
|
|||||||
public slab_allocated<message, 1>
|
public slab_allocated<message, 1>
|
||||||
{
|
{
|
||||||
uint64_t tag;
|
uint64_t tag;
|
||||||
uint64_t badge;
|
uint64_t subtag;
|
||||||
|
|
||||||
uint16_t reply_tag;
|
uint16_t reply_tag;
|
||||||
|
|
||||||
uint16_t reserved0;
|
|
||||||
uint16_t reserved1;
|
|
||||||
|
|
||||||
uint8_t handle_count;
|
uint8_t handle_count;
|
||||||
uint8_t data_len;
|
|
||||||
|
|
||||||
handle handles[mailbox::max_handle_count];
|
j6_handle_t handles[mailbox::max_handle_count];
|
||||||
uint8_t data[mailbox::max_data_length];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class mailbox::replyer
|
class mailbox::replyer
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "capabilities.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
@@ -19,17 +20,16 @@ namespace obj {
|
|||||||
|
|
||||||
process::process() :
|
process::process() :
|
||||||
kobject {kobject::type::process},
|
kobject {kobject::type::process},
|
||||||
m_next_handle {1},
|
|
||||||
m_state {state::running}
|
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
|
// The "kernel process"-only constructor
|
||||||
process::process(page_table *kpml4) :
|
process::process(page_table *kpml4) :
|
||||||
kobject {kobject::type::process},
|
kobject {kobject::type::process},
|
||||||
m_space {kpml4},
|
m_space {kpml4},
|
||||||
m_next_handle {self_handle()+1},
|
|
||||||
m_state {state::running}
|
m_state {state::running}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -121,51 +121,40 @@ process::thread_exited(thread *th)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_handle_t
|
void
|
||||||
process::add_handle(kobject *obj, j6_cap_t caps)
|
process::add_handle(j6_handle_t handle)
|
||||||
{
|
{
|
||||||
if (!obj)
|
m_handles.add(handle);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
process::remove_handle(j6_handle_t id)
|
process::remove_handle(j6_handle_t id)
|
||||||
{
|
{
|
||||||
return m_handles.erase(id);
|
return m_handles.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle *
|
bool
|
||||||
process::lookup_handle(j6_handle_t id)
|
process::has_handle(j6_handle_t id)
|
||||||
{
|
{
|
||||||
return m_handles.find(id);
|
return m_handles.contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
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) {
|
size_t count = 0;
|
||||||
if (len-- == 0)
|
for (j6_handle_t handle : m_handles) {
|
||||||
break;
|
|
||||||
*handles++ = i.key;
|
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();
|
return m_handles.count();
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
#include <j6/cap_flags.h>
|
#include <j6/cap_flags.h>
|
||||||
#include <util/map.h>
|
#include <util/map.h>
|
||||||
|
#include <util/node_map.h>
|
||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include "objects/handle.h"
|
#include "heap_allocator.h"
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
#include "page_table.h"
|
#include "page_table.h"
|
||||||
#include "vm_space.h"
|
#include "vm_space.h"
|
||||||
@@ -59,32 +60,25 @@ public:
|
|||||||
/// \returns The newly created thread object
|
/// \returns The newly created thread object
|
||||||
thread * create_thread(uintptr_t rsp3 = 0, uint8_t priorty = default_priority);
|
thread * create_thread(uintptr_t rsp3 = 0, uint8_t priorty = default_priority);
|
||||||
|
|
||||||
/// Start tracking an object with a handle.
|
/// Give this process access to an object capability handle
|
||||||
/// \args obj The object this handle refers to
|
/// \args handle A handle to give this process access to
|
||||||
/// \args caps The capabilities on this handle
|
void add_handle(j6_handle_t handle);
|
||||||
/// \returns The new handle id for this object
|
|
||||||
j6_handle_t add_handle(kobject *obj, j6_cap_t caps);
|
|
||||||
|
|
||||||
/// Start tracking an object with a handle.
|
/// Remove access to an object capability from this process
|
||||||
/// \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.
|
|
||||||
/// \args handle The handle that refers to the object
|
/// \args handle The handle that refers to the object
|
||||||
/// \returns True if the handle was removed
|
/// \returns True if the handle was removed
|
||||||
bool remove_handle(j6_handle_t handle);
|
bool remove_handle(j6_handle_t handle);
|
||||||
|
|
||||||
/// Lookup an object for a handle
|
/// Return whether this process has access to the given object capability
|
||||||
/// \args handle The handle to the object
|
/// \args handle The handle to the capability
|
||||||
/// \returns Pointer to the handle struct, or null if not found
|
/// \returns True if the process has been given access to that capability
|
||||||
handle * lookup_handle(j6_handle_t handle);
|
bool has_handle(j6_handle_t handle);
|
||||||
|
|
||||||
/// Get the list of handle ids this process owns
|
/// 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
|
/// \arg len Size of the array
|
||||||
/// \returns Total number of handles (may be more than number copied)
|
/// \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
|
/// Inform the process of an exited thread
|
||||||
/// \args th The thread which has exited
|
/// \args th The thread which has exited
|
||||||
@@ -119,8 +113,7 @@ private:
|
|||||||
|
|
||||||
util::vector<thread*> m_threads;
|
util::vector<thread*> m_threads;
|
||||||
|
|
||||||
j6_handle_t m_next_handle;
|
util::node_set<j6_handle_t, j6_handle_invalid, heap_allocated> m_handles;
|
||||||
util::map<j6_handle_t, handle> m_handles;
|
|
||||||
|
|
||||||
enum class state : uint8_t { running, exited };
|
enum class state : uint8_t { running, exited };
|
||||||
state m_state;
|
state m_state;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
|
|
||||||
|
#include "capabilities.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
@@ -31,7 +32,8 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
|||||||
m_tcb.rsp0 = rsp0;
|
m_tcb.rsp0 = rsp0;
|
||||||
|
|
||||||
m_creator = current_cpu().thread;
|
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()
|
thread::~thread()
|
||||||
|
|||||||
@@ -87,10 +87,10 @@ for id, scope, method in syscalls.methods:
|
|||||||
else:
|
else:
|
||||||
name = f"{method.name}"
|
name = f"{method.name}"
|
||||||
|
|
||||||
args = []
|
args = [] # The function call args to call the impl
|
||||||
argdefs = []
|
argdefs = [] # The user-facing syscall args signature
|
||||||
cxxargdefs = []
|
cxxargdefs = [] # The kernel syscall impl args signature
|
||||||
refparams = []
|
refparams = [] # The list of params which are kobjects
|
||||||
|
|
||||||
handles = []
|
handles = []
|
||||||
objparams = []
|
objparams = []
|
||||||
@@ -105,8 +105,7 @@ for id, scope, method in syscalls.methods:
|
|||||||
argdefs.append(("j6_handle_t", "self"))
|
argdefs.append(("j6_handle_t", "self"))
|
||||||
|
|
||||||
if "handle" in method.options:
|
if "handle" in method.options:
|
||||||
args.append("self_handle")
|
args.append("self")
|
||||||
cxxargdefs.append(f"obj::handle *self_handle")
|
|
||||||
else:
|
else:
|
||||||
args.append("self_obj")
|
args.append("self_obj")
|
||||||
cxxargdefs.append(f"obj::{scope.cname} *self")
|
cxxargdefs.append(f"obj::{scope.cname} *self")
|
||||||
@@ -131,11 +130,8 @@ for id, scope, method in syscalls.methods:
|
|||||||
objparams.append((type, arg))
|
objparams.append((type, arg))
|
||||||
args.append(f"{arg}_obj")
|
args.append(f"{arg}_obj")
|
||||||
cxxargdefs.append(f"{type} {arg}")
|
cxxargdefs.append(f"{type} {arg}")
|
||||||
else:
|
|
||||||
args.append(f"{arg}_handle")
|
|
||||||
cxxargdefs.append(f"obj::handle *{arg}_handle")
|
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
cxxargdefs.append(f"{type} {arg}")
|
cxxargdefs.append(f"{type} {arg}")
|
||||||
args.append(arg)
|
args.append(arg)
|
||||||
|
|
||||||
@@ -174,21 +170,17 @@ for id, scope, method in syscalls.methods:
|
|||||||
cog.outl( " return j6_err_invalid_arg;")
|
cog.outl( " return j6_err_invalid_arg;")
|
||||||
cog.outl()
|
cog.outl()
|
||||||
|
|
||||||
|
if handles:
|
||||||
|
cog.outl(f" j6_status_t res;")
|
||||||
|
|
||||||
for type, arg, caps in handles:
|
for type, arg, caps in handles:
|
||||||
cog.outl(f" obj::handle *{arg}_handle = get_handle<typename obj::{type}>({arg});")
|
capsval = "0"
|
||||||
cog.outl(f" if (!{arg}_handle) return j6_err_invalid_arg;")
|
|
||||||
|
|
||||||
if caps:
|
if caps:
|
||||||
allcaps = " | ".join(caps)
|
capsval = " | ".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;")
|
|
||||||
|
|
||||||
for type, arg in objparams:
|
cog.outl(f" obj::{type} *{arg}_obj = nullptr;")
|
||||||
if type.endswith('*'):
|
cog.outl(f" res = get_handle<typename obj::{type}>({arg}, {capsval}, {arg}_obj);")
|
||||||
type = type[:-1].strip()
|
cog.outl(f" if (res != j6_status_ok) return res;")
|
||||||
|
|
||||||
cog.outl(f" {type} *{arg}_obj = {arg}_handle->as<typename {type}>();")
|
|
||||||
cog.outl(f" if (!{arg}_obj) return j6_err_invalid_arg;")
|
|
||||||
cog.outl()
|
cog.outl()
|
||||||
|
|
||||||
if "noreturn" in method.options:
|
if "noreturn" in method.options:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using namespace obj;
|
|||||||
namespace syscalls {
|
namespace syscalls {
|
||||||
|
|
||||||
j6_status_t
|
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();
|
process &p = process::current();
|
||||||
size_t requested = *handles_len;
|
size_t requested = *handles_len;
|
||||||
@@ -23,12 +23,11 @@ handle_list(j6_handle_t *handles, size_t *handles_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
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();
|
process &p = process::current();
|
||||||
*clone = p.add_handle(
|
p.add_handle(*clone);
|
||||||
orig->object,
|
|
||||||
orig->caps() & mask);
|
|
||||||
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
|
|
||||||
|
#include "capabilities.h"
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
|
|
||||||
@@ -12,41 +13,43 @@ namespace syscalls {
|
|||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T * construct_handle(j6_handle_t *id, Args... args)
|
T * construct_handle(j6_handle_t *id, Args... args)
|
||||||
{
|
{
|
||||||
obj::process &p = obj::process::current();
|
|
||||||
T *o = new T {args...};
|
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;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
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::process &p = obj::process::current();
|
||||||
obj::handle *h = p.lookup_handle(id);
|
if (!p.has_handle(id) || (capdata->caps & caps) != caps)
|
||||||
if (!h || h->type() != T::type)
|
return j6_err_denied;
|
||||||
return nullptr;
|
|
||||||
return h;
|
object = static_cast<T*>(capdata->object);
|
||||||
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline obj::handle * get_handle<obj::kobject>(j6_handle_t id)
|
inline j6_status_t get_handle<obj::kobject>(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();
|
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 <typename T>
|
} // namespace syscalls
|
||||||
T * remove_handle(j6_handle_t id)
|
|
||||||
{
|
|
||||||
obj::handle *h = get_handle<T>(id);
|
|
||||||
T *o = nullptr;
|
|
||||||
|
|
||||||
if (h) {
|
|
||||||
o = h->object;
|
|
||||||
obj::process &p = obj::process::current();
|
|
||||||
p.remove_handle(id);
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -31,30 +31,20 @@ j6_status_t
|
|||||||
prep_send(
|
prep_send(
|
||||||
mailbox::message *msg,
|
mailbox::message *msg,
|
||||||
uint64_t tag,
|
uint64_t tag,
|
||||||
uint64_t badge,
|
uint64_t subtag,
|
||||||
const void *data,
|
|
||||||
size_t data_len,
|
|
||||||
const j6_handle_t *handles,
|
const j6_handle_t *handles,
|
||||||
size_t handle_count)
|
size_t handle_count)
|
||||||
{
|
{
|
||||||
if (!msg ||
|
if (!msg ||
|
||||||
data_len > mailbox::max_data_length ||
|
|
||||||
handle_count > mailbox::max_handle_count)
|
handle_count > mailbox::max_handle_count)
|
||||||
return j6_err_invalid_arg;
|
return j6_err_invalid_arg;
|
||||||
|
|
||||||
msg->tag = tag;
|
msg->tag = tag;
|
||||||
msg->badge = badge;
|
msg->subtag = subtag;
|
||||||
|
|
||||||
msg->handle_count = handle_count;
|
msg->handle_count = handle_count;
|
||||||
for (unsigned i = 0; i < handle_count; ++i) {
|
memcpy(msg->handles, handles, sizeof(j6_handle_t) * handle_count);
|
||||||
handle const *h = get_handle<kobject>(handles[i]);
|
|
||||||
if (!h)
|
|
||||||
return j6_err_invalid_arg;
|
|
||||||
msg->handles[i] = *h;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->data_len = data_len;
|
|
||||||
memcpy(msg->data, data, data_len);
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,43 +52,35 @@ void
|
|||||||
prep_receive(
|
prep_receive(
|
||||||
mailbox::message *msg,
|
mailbox::message *msg,
|
||||||
uint64_t *tag,
|
uint64_t *tag,
|
||||||
uint64_t *badge,
|
uint64_t *subtag,
|
||||||
uint16_t *reply_tag,
|
uint16_t *reply_tag,
|
||||||
void *data,
|
|
||||||
size_t *data_len,
|
|
||||||
j6_handle_t *handles,
|
j6_handle_t *handles,
|
||||||
size_t *handle_count)
|
size_t *handle_count)
|
||||||
{
|
{
|
||||||
if (tag) *tag = msg->tag;
|
if (tag) *tag = msg->tag;
|
||||||
if (badge) *badge = msg->badge;
|
if (subtag) *subtag = msg->subtag;
|
||||||
if (reply_tag) *reply_tag = msg->reply_tag;
|
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;
|
*handle_count = msg->handle_count;
|
||||||
process &proc = process::current();
|
process &proc = process::current();
|
||||||
for (size_t i = 0; i < msg->handle_count; ++i) {
|
for (size_t i = 0; i < msg->handle_count; ++i) {
|
||||||
handles[i] = proc.add_handle(msg->handles[i]);
|
proc.add_handle(msg->handles[i]);
|
||||||
msg->handles[i] = {};
|
handles[i] = msg->handles[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
mailbox_send(
|
mailbox_send(
|
||||||
handle *self_handle,
|
mailbox *self,
|
||||||
uint64_t tag,
|
uint64_t tag,
|
||||||
const void * data,
|
uint64_t subtag,
|
||||||
size_t data_len,
|
|
||||||
j6_handle_t * handles,
|
j6_handle_t * handles,
|
||||||
size_t handle_count)
|
size_t handle_count)
|
||||||
{
|
{
|
||||||
mailbox *self = self_handle->as<mailbox>();
|
|
||||||
mailbox::message *msg = new mailbox::message;
|
mailbox::message *msg = new mailbox::message;
|
||||||
|
|
||||||
j6_status_t s = prep_send(msg,
|
j6_status_t s = prep_send(msg,
|
||||||
tag, self_handle->badge,
|
tag, subtag,
|
||||||
data, data_len,
|
|
||||||
handles, handle_count);
|
handles, handle_count);
|
||||||
|
|
||||||
if (s != j6_status_ok) {
|
if (s != j6_status_ok) {
|
||||||
@@ -115,16 +97,13 @@ j6_status_t
|
|||||||
mailbox_receive(
|
mailbox_receive(
|
||||||
mailbox *self,
|
mailbox *self,
|
||||||
uint64_t *tag,
|
uint64_t *tag,
|
||||||
void * data,
|
uint64_t *subtag,
|
||||||
size_t * data_len,
|
|
||||||
j6_handle_t *handles,
|
j6_handle_t *handles,
|
||||||
size_t *handle_count,
|
size_t *handle_count,
|
||||||
uint16_t *reply_tag,
|
uint16_t *reply_tag,
|
||||||
uint64_t * badge,
|
|
||||||
uint64_t flags)
|
uint64_t flags)
|
||||||
{
|
{
|
||||||
if (*data_len < mailbox::max_data_length ||
|
if (*handle_count < mailbox::max_handle_count)
|
||||||
*handle_count < mailbox::max_handle_count)
|
|
||||||
return j6_err_insufficient;
|
return j6_err_insufficient;
|
||||||
|
|
||||||
mailbox::message *msg = nullptr;
|
mailbox::message *msg = nullptr;
|
||||||
@@ -138,8 +117,7 @@ mailbox_receive(
|
|||||||
}
|
}
|
||||||
|
|
||||||
prep_receive(msg,
|
prep_receive(msg,
|
||||||
tag, badge, reply_tag,
|
tag, subtag, reply_tag,
|
||||||
data, data_len,
|
|
||||||
handles, handle_count);
|
handles, handle_count);
|
||||||
|
|
||||||
if (*reply_tag == 0)
|
if (*reply_tag == 0)
|
||||||
@@ -150,19 +128,16 @@ mailbox_receive(
|
|||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
mailbox_call(
|
mailbox_call(
|
||||||
handle *self_handle,
|
mailbox *self,
|
||||||
uint64_t *tag,
|
uint64_t *tag,
|
||||||
void * data,
|
uint64_t *subtag,
|
||||||
size_t * data_len,
|
|
||||||
j6_handle_t *handles,
|
j6_handle_t *handles,
|
||||||
size_t *handle_count)
|
size_t *handle_count)
|
||||||
{
|
{
|
||||||
mailbox *self = self_handle->as<mailbox>();
|
|
||||||
mailbox::message *msg = new mailbox::message;
|
mailbox::message *msg = new mailbox::message;
|
||||||
|
|
||||||
j6_status_t s = prep_send(msg,
|
j6_status_t s = prep_send(msg,
|
||||||
*tag, self_handle->badge,
|
*tag, *subtag,
|
||||||
data, *data_len,
|
|
||||||
handles, *handle_count);
|
handles, *handle_count);
|
||||||
|
|
||||||
if (s != j6_status_ok) {
|
if (s != j6_status_ok) {
|
||||||
@@ -177,8 +152,7 @@ mailbox_call(
|
|||||||
}
|
}
|
||||||
|
|
||||||
prep_receive(msg,
|
prep_receive(msg,
|
||||||
tag, nullptr, nullptr,
|
tag, subtag, 0,
|
||||||
data, data_len,
|
|
||||||
handles, handle_count);
|
handles, handle_count);
|
||||||
|
|
||||||
delete msg;
|
delete msg;
|
||||||
@@ -190,8 +164,7 @@ j6_status_t
|
|||||||
mailbox_respond(
|
mailbox_respond(
|
||||||
mailbox *self,
|
mailbox *self,
|
||||||
uint64_t tag,
|
uint64_t tag,
|
||||||
const void * data,
|
uint64_t subtag,
|
||||||
size_t data_len,
|
|
||||||
j6_handle_t * handles,
|
j6_handle_t * handles,
|
||||||
size_t handle_count,
|
size_t handle_count,
|
||||||
uint16_t reply_tag)
|
uint16_t reply_tag)
|
||||||
@@ -200,8 +173,7 @@ mailbox_respond(
|
|||||||
if (!reply.valid())
|
if (!reply.valid())
|
||||||
return j6_err_invalid_arg;
|
return j6_err_invalid_arg;
|
||||||
|
|
||||||
j6_status_t s = prep_send(reply.msg, tag, 0,
|
j6_status_t s = prep_send(reply.msg, tag, subtag,
|
||||||
data, data_len,
|
|
||||||
handles, handle_count);
|
handles, handle_count);
|
||||||
|
|
||||||
if (s != j6_status_ok) {
|
if (s != j6_status_ok) {
|
||||||
@@ -217,21 +189,18 @@ j6_status_t
|
|||||||
mailbox_respond_receive(
|
mailbox_respond_receive(
|
||||||
mailbox *self,
|
mailbox *self,
|
||||||
uint64_t *tag,
|
uint64_t *tag,
|
||||||
void * data,
|
uint64_t *subtag,
|
||||||
size_t * data_len,
|
|
||||||
size_t data_in,
|
|
||||||
j6_handle_t *handles,
|
j6_handle_t *handles,
|
||||||
size_t *handle_count,
|
size_t *handle_count,
|
||||||
size_t handles_in,
|
size_t handles_in,
|
||||||
uint16_t *reply_tag,
|
uint16_t *reply_tag,
|
||||||
uint64_t * badge,
|
|
||||||
uint64_t flags)
|
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)
|
if (s != j6_status_ok)
|
||||||
return s;
|
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)
|
if (s != j6_status_ok)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,9 @@ process_exit(int32_t status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
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());
|
self->add_handle(target);
|
||||||
if (received)
|
|
||||||
*received = out;
|
|
||||||
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,26 +12,26 @@
|
|||||||
j6_handle_t __handle_self;
|
j6_handle_t __handle_self;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr size_t static_arr_size = 8;
|
constexpr size_t static_arr_count = 8;
|
||||||
j6_handle_t handle_array[static_arr_size];
|
j6_handle_descriptor handle_array[static_arr_count];
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
j6_handle_t
|
j6_handle_t
|
||||||
j6_find_first_handle(j6_object_type obj_type)
|
j6_find_first_handle(j6_object_type obj_type)
|
||||||
{
|
{
|
||||||
size_t count = static_arr_size;
|
size_t count = static_arr_count;
|
||||||
j6_handle_t *handles = handle_array;
|
j6_handle_descriptor *handles = handle_array;
|
||||||
j6_status_t s = j6_handle_list(handles, &count);
|
j6_status_t s = j6_handle_list(handles, &count);
|
||||||
|
|
||||||
if (s != j6_err_insufficient && s != j6_status_ok)
|
if (s != j6_err_insufficient && s != j6_status_ok)
|
||||||
return j6_handle_invalid;
|
return j6_handle_invalid;
|
||||||
|
|
||||||
if (count > static_arr_size)
|
if (count > static_arr_count)
|
||||||
count = static_arr_size;
|
count = static_arr_count;
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
for (size_t i = 0; i < count; ++i) {
|
||||||
uint8_t type = (handles[i] >> 56);
|
j6_handle_descriptor &desc = handle_array[i];
|
||||||
if (type == obj_type) return handles[i];
|
if (desc.type == obj_type) return desc.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
return j6_handle_invalid;
|
return j6_handle_invalid;
|
||||||
|
|||||||
@@ -27,15 +27,12 @@ typedef uint64_t j6_tag_t;
|
|||||||
#define j6_tag_from_irq(x) ((x) | j6_tag_irq_base)
|
#define j6_tag_from_irq(x) ((x) | j6_tag_irq_base)
|
||||||
#define j6_tag_to_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
|
/// Handles are references and capabilities to other objects.
|
||||||
/// an id in the lower 32 bits, a bitfield of capabilities in bits 32-55
|
|
||||||
/// and a type id in bits 56-63.
|
|
||||||
typedef uint64_t j6_handle_t;
|
typedef uint64_t j6_handle_t;
|
||||||
|
#define j6_handle_invalid 0
|
||||||
|
|
||||||
/// Bitfield for storage of capabilities on their own
|
/// Bitfield for storage of capabilities on their own
|
||||||
typedef uint32_t j6_cap_t;
|
typedef uint16_t j6_cap_t;
|
||||||
|
|
||||||
#define j6_handle_invalid ((j6_handle_t)-1)
|
|
||||||
|
|
||||||
enum j6_object_type {
|
enum j6_object_type {
|
||||||
#define OBJECT_TYPE( name, val ) j6_object_type_ ## name = val,
|
#define OBJECT_TYPE( name, val ) j6_object_type_ ## name = val,
|
||||||
@@ -44,3 +41,12 @@ enum j6_object_type {
|
|||||||
|
|
||||||
j6_object_type_max
|
j6_object_type_max
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Description of a handle
|
||||||
|
struct j6_handle_descriptor
|
||||||
|
{
|
||||||
|
j6_handle_t handle;
|
||||||
|
j6_cap_t caps;
|
||||||
|
j6_object_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,16 +60,15 @@ channel_pump_loop()
|
|||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
uint64_t tag = j6_proto_sl_register;
|
uint64_t tag = j6_proto_sl_register;
|
||||||
uint64_t data = "jsix.protocol.stream.ouput"_id;
|
uint64_t proto_id = "jsix.protocol.stream.ouput"_id;
|
||||||
size_t data_len = sizeof(data);
|
|
||||||
size_t handle_count = 1;
|
size_t handle_count = 1;
|
||||||
result = j6_mailbox_call(slp, &tag,
|
result = j6_mailbox_call(slp,
|
||||||
&data, &data_len,
|
&tag, &proto_id,
|
||||||
&cout_write, &handle_count);
|
&cout_write, &handle_count);
|
||||||
if (result != j6_status_ok)
|
if (result != j6_status_ok)
|
||||||
return 4;
|
return 4;
|
||||||
|
|
||||||
if (tag != j6_proto_base_status || data != j6_status_ok)
|
if (tag != j6_proto_base_status)
|
||||||
return 5;
|
return 5;
|
||||||
|
|
||||||
result = j6_system_request_iopl(g_handle_sys, 3);
|
result = j6_system_request_iopl(g_handle_sys, 3);
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ load_program(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_process_give_handle(proc, sys, nullptr);
|
res = j6_process_give_handle(proc, sys);
|
||||||
if (res != j6_status_ok) {
|
if (res != j6_status_ok) {
|
||||||
sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", prog.filename, res);
|
sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", prog.filename, res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_process_give_handle(proc, slp, nullptr);
|
res = j6_process_give_handle(proc, slp);
|
||||||
if (res != j6_status_ok) {
|
if (res != j6_status_ok) {
|
||||||
sprintf(err_msg, " ** error loading program '%s': giving SLP handle: %lx", prog.filename, res);
|
sprintf(err_msg, " ** error loading program '%s': giving SLP handle: %lx", prog.filename, res);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -5,71 +5,72 @@
|
|||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
#include <j6/protocols/service_locator.h>
|
#include <j6/protocols/service_locator.h>
|
||||||
#include <j6/syscalls.h>
|
#include <j6/syscalls.h>
|
||||||
#include <util/map.h>
|
#include <util/node_map.h>
|
||||||
|
|
||||||
#include "service_locator.h"
|
#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
|
void
|
||||||
service_locator_start(j6_handle_t mb)
|
service_locator_start(j6_handle_t mb)
|
||||||
{
|
{
|
||||||
// TODO: This should be a multimap
|
// TODO: This should be a multimap
|
||||||
util::map<uint64_t, j6_handle_t> services;
|
util::node_map<uint64_t, handle_entry> services;
|
||||||
|
|
||||||
uint64_t tag;
|
uint64_t tag;
|
||||||
|
uint64_t subtag;
|
||||||
uint16_t reply_tag;
|
uint16_t reply_tag;
|
||||||
|
|
||||||
uint8_t data[100];
|
|
||||||
size_t data_len = sizeof(data);
|
|
||||||
|
|
||||||
j6_handle_t handles[10];
|
j6_handle_t handles[10];
|
||||||
size_t handles_count = sizeof(handles)/sizeof(j6_handle_t);
|
size_t handles_count = sizeof(handles)/sizeof(j6_handle_t);
|
||||||
|
|
||||||
j6_status_t s = j6_mailbox_receive(mb, &tag,
|
j6_status_t s = j6_mailbox_receive(mb,
|
||||||
data, &data_len,
|
&tag, &subtag,
|
||||||
handles, &handles_count,
|
handles, &handles_count,
|
||||||
&reply_tag, nullptr,
|
&reply_tag,
|
||||||
j6_mailbox_block);
|
j6_mailbox_block);
|
||||||
|
|
||||||
uint64_t proto_id;
|
uint64_t proto_id;
|
||||||
uint64_t *data_words = reinterpret_cast<uint64_t*>(data);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
j6_handle_t *found = nullptr;
|
handle_entry *found = nullptr;
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case j6_proto_base_get_proto_id:
|
case j6_proto_base_get_proto_id:
|
||||||
tag = j6_proto_base_proto_id;
|
tag = j6_proto_base_proto_id;
|
||||||
*data_words = j6_proto_sl_id;
|
subtag = j6_proto_sl_id;
|
||||||
data_len = sizeof(j6_status_t);
|
|
||||||
handles_count = 0;
|
handles_count = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case j6_proto_sl_register:
|
case j6_proto_sl_register:
|
||||||
proto_id = *data_words;
|
proto_id = subtag;
|
||||||
if (handles_count != 1) {
|
if (handles_count != 1) {
|
||||||
tag = j6_proto_base_status;
|
tag = j6_proto_base_status;
|
||||||
*data_words = j6_err_invalid_arg;
|
subtag = j6_err_invalid_arg;
|
||||||
data_len = sizeof(j6_status_t);
|
|
||||||
handles_count = 0;
|
handles_count = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
services.insert( proto_id, handles[0] );
|
services.insert( {proto_id, handles[0]} );
|
||||||
tag = j6_proto_base_status;
|
tag = j6_proto_base_status;
|
||||||
*data_words = j6_status_ok;
|
subtag = j6_status_ok;
|
||||||
data_len = sizeof(j6_status_t);
|
|
||||||
handles_count = 0;
|
handles_count = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case j6_proto_sl_find:
|
case j6_proto_sl_find:
|
||||||
proto_id = *data_words;
|
proto_id = subtag;
|
||||||
tag = j6_proto_sl_result;
|
tag = j6_proto_sl_result;
|
||||||
data_len = 0;
|
|
||||||
|
|
||||||
found = services.find(proto_id);
|
found = services.find(proto_id);
|
||||||
if (found) {
|
if (found) {
|
||||||
handles_count = 1;
|
handles_count = 1;
|
||||||
handles[0] = *found;
|
handles[0] = found->handle;
|
||||||
} else {
|
} else {
|
||||||
handles_count = 0;
|
handles_count = 0;
|
||||||
}
|
}
|
||||||
@@ -77,21 +78,18 @@ service_locator_start(j6_handle_t mb)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
tag = j6_proto_base_status;
|
tag = j6_proto_base_status;
|
||||||
*data_words = j6_err_invalid_arg;
|
subtag = j6_err_invalid_arg;
|
||||||
data_len = sizeof(j6_status_t);
|
|
||||||
handles_count = 0;
|
handles_count = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t data_in = data_len;
|
|
||||||
size_t handles_in = handles_count;
|
size_t handles_in = handles_count;
|
||||||
data_len = sizeof(data);
|
|
||||||
handles_count = sizeof(handles)/sizeof(j6_handle_t);
|
handles_count = sizeof(handles)/sizeof(j6_handle_t);
|
||||||
|
|
||||||
s = j6_mailbox_respond_receive(mb, &tag,
|
s = j6_mailbox_respond_receive(mb,
|
||||||
data, &data_len, data_in,
|
&tag, &subtag,
|
||||||
handles, &handles_count, handles_in,
|
handles, &handles_count, handles_in,
|
||||||
&reply_tag, nullptr,
|
&reply_tag,
|
||||||
j6_mailbox_block);
|
j6_mailbox_block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ main(int argc, const char **argv)
|
|||||||
{
|
{
|
||||||
j6_log("logging server starting");
|
j6_log("logging server starting");
|
||||||
|
|
||||||
j6_status_t result = j6_status_ok;
|
|
||||||
|
|
||||||
g_handle_sys = j6_find_first_handle(j6_object_type_system);
|
g_handle_sys = j6_find_first_handle(j6_object_type_system);
|
||||||
if (g_handle_sys == j6_handle_invalid)
|
if (g_handle_sys == j6_handle_invalid)
|
||||||
@@ -123,22 +122,20 @@ main(int argc, const char **argv)
|
|||||||
|
|
||||||
j6_handle_t cout = j6_handle_invalid;
|
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 tag = j6_proto_sl_find;
|
||||||
uint64_t proto_id = "jsix.protocol.stream.ouput"_id;
|
uint64_t proto_id = "jsix.protocol.stream.ouput"_id;
|
||||||
size_t data_len = sizeof(proto_id);
|
|
||||||
size_t handle_count = 0;
|
size_t handle_count = 0;
|
||||||
|
|
||||||
result = j6_mailbox_call(slp, &tag,
|
j6_status_t s = j6_mailbox_call(slp, &tag,
|
||||||
&proto_id, &data_len,
|
&proto_id, &cout, &handle_count);
|
||||||
&cout, &handle_count);
|
if (s == j6_status_ok &&
|
||||||
if (result == j6_status_ok &&
|
|
||||||
tag == j6_proto_sl_result &&
|
tag == j6_proto_sl_result &&
|
||||||
handle_count == 1)
|
handle_count == 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
cout = j6_handle_invalid;
|
cout = j6_handle_invalid;
|
||||||
j6_thread_sleep(1000); // 1ms
|
j6_thread_sleep(10000); // 10ms
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cout == j6_handle_invalid)
|
if (cout == j6_handle_invalid)
|
||||||
|
|||||||
@@ -24,19 +24,16 @@ TEST_CASE( mailbox_tests, would_block )
|
|||||||
CHECK( s == j6_status_ok, "Could not create a mailbox" );
|
CHECK( s == j6_status_ok, "Could not create a mailbox" );
|
||||||
|
|
||||||
uint64_t tag = 12345;
|
uint64_t tag = 12345;
|
||||||
uint8_t buffer[128];
|
uint64_t subtag = 67890;
|
||||||
size_t buffer_size = 128;
|
|
||||||
j6_handle_t handles[10];
|
j6_handle_t handles[10];
|
||||||
size_t handle_count = 10;
|
size_t handle_count = 10;
|
||||||
uint16_t reply_tag = 0;
|
uint16_t reply_tag = 0;
|
||||||
uint64_t badge = 0;
|
|
||||||
uint64_t flags = 0;
|
uint64_t flags = 0;
|
||||||
|
|
||||||
s = j6_mailbox_receive( mb, &tag,
|
s = j6_mailbox_receive( mb,
|
||||||
buffer, &buffer_size,
|
&tag, &subtag,
|
||||||
handles, &handle_count,
|
handles, &handle_count,
|
||||||
&reply_tag, &badge,
|
&reply_tag, flags );
|
||||||
flags );
|
|
||||||
CHECK( s == j6_status_would_block, "Should have gotten would block error" );
|
CHECK( s == j6_status_would_block, "Should have gotten would block error" );
|
||||||
|
|
||||||
j6_mailbox_close(mb);
|
j6_mailbox_close(mb);
|
||||||
@@ -51,37 +48,29 @@ TEST_CASE( mailbox_tests, send_receive )
|
|||||||
CHECK( s == j6_status_ok, "Could not create a mailbox" );
|
CHECK( s == j6_status_ok, "Could not create a mailbox" );
|
||||||
|
|
||||||
uint64_t out_tag = 12345;
|
uint64_t out_tag = 12345;
|
||||||
uint8_t out_buffer[128] = {2, 4, 6, 8, 10, 12, 14};
|
uint64_t out_subtag = 67890;
|
||||||
size_t out_buffer_size = 7;
|
|
||||||
j6_handle_t out_handles[10];
|
j6_handle_t out_handles[10];
|
||||||
size_t out_handle_count = 0;
|
size_t out_handle_count = 0;
|
||||||
|
|
||||||
s = j6_mailbox_send( mb, out_tag,
|
s = j6_mailbox_send( mb, out_tag, out_subtag,
|
||||||
out_buffer, out_buffer_size,
|
|
||||||
out_handles, out_handle_count );
|
out_handles, out_handle_count );
|
||||||
CHECK( s == j6_status_ok, "Did not send successfully" );
|
CHECK( s == j6_status_ok, "Did not send successfully" );
|
||||||
|
|
||||||
uint64_t in_tag = 0;
|
uint64_t in_tag = 0;
|
||||||
uint8_t in_buffer[128];
|
uint64_t in_subtag = 0;
|
||||||
size_t in_buffer_size = 128;
|
|
||||||
j6_handle_t in_handles[10];
|
j6_handle_t in_handles[10];
|
||||||
size_t in_handle_count = 10;
|
size_t in_handle_count = 10;
|
||||||
uint16_t in_reply_tag = 0;
|
uint16_t in_reply_tag = 0;
|
||||||
uint64_t in_badge = 0;
|
|
||||||
uint64_t in_flags = 0;
|
uint64_t in_flags = 0;
|
||||||
|
|
||||||
s = j6_mailbox_receive( mb, &in_tag,
|
s = j6_mailbox_receive( mb, &in_tag, &in_subtag,
|
||||||
in_buffer, &in_buffer_size,
|
|
||||||
in_handles, &in_handle_count,
|
in_handles, &in_handle_count,
|
||||||
&in_reply_tag, &in_badge,
|
&in_reply_tag, in_flags );
|
||||||
in_flags );
|
|
||||||
CHECK( s == j6_status_ok, "Did not receive successfully" );
|
CHECK( s == j6_status_ok, "Did not receive successfully" );
|
||||||
|
|
||||||
CHECK_BARE( in_tag == out_tag );
|
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( in_handle_count == out_handle_count );
|
||||||
|
|
||||||
CHECK_BARE( memcmp(out_buffer, in_buffer, in_buffer_size) == 0 );
|
|
||||||
|
|
||||||
j6_mailbox_close(mb);
|
j6_mailbox_close(mb);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user