[kernel] Pass objects not handles to syscall impls

This commit contains a couple large, interdependent changes:

- In preparation for capability checking, the _syscall_verify_*
  functions now load most handles passed in, and verify that they exist
  and are of the correct type. Lists and out-handles are not converted
  to objects.
- Also in preparation for capability checking, the internal
  representation of handles has changed. j6_handle_t is now 32 bits, and
  a new j6_cap_t (also 32 bits) is added. Handles of a process are now a
  util::map<j6_handle_t, handle> where handle is a new struct containing
  the id, capabilities, and object pointer.
- The kernel object definition DSL gained a few changes to support auto
  generating the handle -> object conversion in the _syscall_verify_*
  functions, mostly knowing the object type, and an optional "cname"
  attribute on objects where their names differ from C++ code.
  (Specifically vma/vm_area)
- Kernel object code and other code under kernel/objects is now in a new
  obj:: namespace, because fuck you <cstdlib> for putting "system" in
  the global namespace. Why even have that header then?
- Kernel object types constructed with the construct_handle helper now
  have a creation_caps static member to declare what capabilities a
  newly created object's handle should have.
This commit is contained in:
Justin C. Miller
2022-01-17 23:23:04 -08:00
parent e0246df26b
commit 1d30322820
50 changed files with 492 additions and 300 deletions

View File

@@ -2,7 +2,7 @@ start: import_statement* (object|interface)+
import_statement: "import" PATH import_statement: "import" PATH
object: description? "object" name options? super? "{" uid method* "}" object: description? "object" name options? super? "{" uid cname? method* "}"
interface: description? "interface" name options? "{" uid interface_param* "}" interface: description? "interface" name options? "{" uid interface_param* "}"
@@ -12,6 +12,8 @@ expose: "expose" type
uid: "uid" UID uid: "uid" UID
cname: "cname" IDENTIFIER
super: ":" name super: ":" name
function: description? "function" name options? ("{" param* "}")? function: description? "function" name options? ("{" param* "}")?

View File

@@ -17,18 +17,10 @@ object process : kobject {
param result int32 # The result to retrun to the parent process param result int32 # The result to retrun to the parent process
} }
# Start the given process running. Note that the entrypoint
# address must be specified in the address space of the new
# process.
method start {
param entrypoint address # The address of the main thread entrypoint
param handles object kobject [list] # A list of parent handles to send to the child process
}
# Give the given process a handle that points to the same # Give the given process a handle that points to the same
# object as the specified handle. # object as the specified handle.
method give_handle { method give_handle {
param sender object kobject # A handle in the caller process to send param target object kobject [handle] # A handle in the caller process to send
param receiver object kobject [out optional] # The handle as the recipient will see it param received object kobject [out optional] # The handle as the recipient will see it
} }
} }

View File

@@ -2,6 +2,7 @@ import "objects/process.def"
object vma : kobject { object vma : kobject {
uid d6a12b63b3ed3937 uid d6a12b63b3ed3937
cname vm_area
method create [constructor] { method create [constructor] {
param size size param size size

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +1,12 @@
from .parser import Transformer, v_args from .parser import Transformer, v_args
def get_opts(args): def get_opts(args):
from .types import Description, Options, Type, UID from .types import CName, Description, Options, Type, UID
kinds = { kinds = {
Description: "desc", Description: "desc",
Options: "opts", Options: "opts",
CName: "cname",
UID: "uid", UID: "uid",
Type: "typename", Type: "typename",
} }
@@ -89,6 +90,11 @@ class DefTransformer(Transformer):
def uid(self, s): def uid(self, s):
return s return s
@v_args(inline=True)
def cname(self, s):
from .types import CName
return CName(s)
@v_args(inline=True) @v_args(inline=True)
def name(self, s): def name(self, s):
return s return s

View File

@@ -2,6 +2,7 @@ def _indent(x):
from textwrap import indent from textwrap import indent
return indent(str(x), ' ') return indent(str(x), ' ')
class CName(str): pass
class Description(str): pass class Description(str): pass
class Import(str): pass class Import(str): pass

View File

@@ -30,7 +30,8 @@ class Interface:
parts.extend(map(_indent, self.functions)) parts.extend(map(_indent, self.functions))
return "\n".join(parts) return "\n".join(parts)
def __methods(self): @property
def methods(self):
mm = [(i, None, self.functions[i]) for i in range(len(self.functions))] mm = [(i, None, self.functions[i]) for i in range(len(self.functions))]
base = len(mm) base = len(mm)
@@ -39,5 +40,3 @@ class Interface:
base += len(o.methods) base += len(o.methods)
return mm return mm
methods = property(__methods)

View File

@@ -2,13 +2,14 @@ from . import _indent
from . import Options from . import Options
class Object: class Object:
def __init__(self, name, uid, typename=None, opts=Options(), desc="", children=tuple()): def __init__(self, name, uid, typename=None, opts=Options(), desc="", children=tuple(), cname=None):
self.name = name self.name = name
self.uid = uid self.uid = uid
self.options = opts self.options = opts
self.desc = desc self.desc = desc
self.super = typename self.super = typename
self.methods = children self.methods = children
self.cname = cname or name
from . import ObjectRef from . import ObjectRef
self.__ref = ObjectRef(name) self.__ref = ObjectRef(name)

View File

@@ -20,11 +20,10 @@ class ObjectRef(Type):
if "list" in options: if "list" in options:
two = "size_t" two = "size_t"
if out:
one = f"const {one} *"
two += " *"
else:
one = f"{one} *" one = f"{one} *"
if out:
two += " *"
return ((one, ""), (two, "_count")) return ((one, ""), (two, "_count"))
else: else:
@@ -33,7 +32,13 @@ class ObjectRef(Type):
return ((one, ""),) return ((one, ""),)
def cxx_names(self, options): def cxx_names(self, options):
if not self.needs_object(options):
return self.c_names(options) return self.c_names(options)
return ((f"obj::{self.name} *", ""),)
def needs_object(self, options):
return not bool({"out", "inout", "list", "handle"}.intersection(options))
@classmethod @classmethod
def connect(cls, objects): def connect(cls, objects):

View File

@@ -11,3 +11,5 @@ class Type:
def cxx_names(self, options): def cxx_names(self, options):
raise NotImplemented("Call to base Type.c_names") raise NotImplemented("Call to base Type.c_names")
def needs_object(self, options):
return False

View File

@@ -73,10 +73,10 @@ cpu_init(cpu_data *cpu, bool bsp)
} }
// Set the initial process as the kernel "process" // Set the initial process as the kernel "process"
extern process &g_kernel_process; extern obj::process &g_kernel_process;
cpu->process = &g_kernel_process; cpu->process = &g_kernel_process;
thread *idle = thread::create_idle_thread( obj::thread *idle = obj::thread::create_idle_thread(
g_kernel_process, g_kernel_process,
scheduler::max_priority, scheduler::max_priority,
cpu->rsp0); cpu->rsp0);

View File

@@ -5,11 +5,14 @@
class GDT; class GDT;
class IDT; class IDT;
class lapic; class lapic;
class process;
struct TCB; struct TCB;
class thread;
class TSS; class TSS;
namespace obj {
class process;
class thread;
}
struct cpu_state struct cpu_state
{ {
uint64_t r15, r14, r13, r12, r11, r10, r9, r8; uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
@@ -47,8 +50,8 @@ struct cpu_data
uintptr_t rsp3; uintptr_t rsp3;
uint64_t rflags3; uint64_t rflags3;
TCB *tcb; TCB *tcb;
thread *thread; obj::thread *thread;
process *process; obj::process *process;
IDT *idt; IDT *idt;
TSS *tss; TSS *tss;
GDT *gdt; GDT *gdt;

View File

@@ -14,7 +14,7 @@
#include "objects/endpoint.h" #include "objects/endpoint.h"
static endpoint * const ignore_endpoint = reinterpret_cast<endpoint*>(-1ull); static obj::endpoint * const ignore_endpoint = reinterpret_cast<obj::endpoint*>(-1ull);
static const char expected_signature[] = "RSD PTR "; static const char expected_signature[] = "RSD PTR ";
@@ -380,7 +380,7 @@ device_manager::dispatch_irq(unsigned irq)
if (irq >= m_irqs.count()) if (irq >= m_irqs.count())
return false; return false;
endpoint *e = m_irqs[irq]; obj::endpoint *e = m_irqs[irq];
if (!e || e == ignore_endpoint) if (!e || e == ignore_endpoint)
return e == ignore_endpoint; return e == ignore_endpoint;
@@ -389,7 +389,7 @@ device_manager::dispatch_irq(unsigned irq)
} }
bool bool
device_manager::bind_irq(unsigned irq, endpoint *target) device_manager::bind_irq(unsigned irq, obj::endpoint *target)
{ {
// TODO: grow if under max size // TODO: grow if under max size
if (irq >= m_irqs.count()) if (irq >= m_irqs.count())
@@ -400,7 +400,7 @@ device_manager::bind_irq(unsigned irq, endpoint *target)
} }
void void
device_manager::unbind_irqs(endpoint *target) device_manager::unbind_irqs(obj::endpoint *target)
{ {
const size_t count = m_irqs.count(); const size_t count = m_irqs.count();
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {

View File

@@ -10,7 +10,10 @@
struct acpi_table_header; struct acpi_table_header;
class block_device; class block_device;
class endpoint;
namespace obj {
class endpoint;
}
using irq_callback = void (*)(void *); using irq_callback = void (*)(void *);
@@ -43,11 +46,11 @@ public:
/// \arg irq The IRQ number to bind /// \arg irq The IRQ number to bind
/// \arg target The endpoint to recieve messages when the IRQ is signalled /// \arg target The endpoint to recieve messages when the IRQ is signalled
/// \returns True on success /// \returns True on success
bool bind_irq(unsigned irq, endpoint *target); bool bind_irq(unsigned irq, obj::endpoint *target);
/// Remove IRQ bindings for an endpoint /// Remove IRQ bindings for an endpoint
/// \arg target The endpoint to remove /// \arg target The endpoint to remove
void unbind_irqs(endpoint *target); void unbind_irqs(obj::endpoint *target);
/// Allocate an MSI IRQ for a device /// Allocate an MSI IRQ for a device
/// \arg name Name of the interrupt, for display to user /// \arg name Name of the interrupt, for display to user
@@ -161,7 +164,7 @@ private:
util::vector<pci_group> m_pci; util::vector<pci_group> m_pci;
util::vector<pci_device> m_devices; util::vector<pci_device> m_devices;
util::vector<endpoint*> m_irqs; util::vector<obj::endpoint*> m_irqs;
util::vector<block_device *> m_blockdevs; util::vector<block_device *> m_blockdevs;

View File

@@ -125,7 +125,7 @@ isr_handler(cpu_state *regs)
static_cast<vm_space::fault_type>(regs->errorcode); static_cast<vm_space::fault_type>(regs->errorcode);
vm_space &space = user vm_space &space = user
? process::current().space() ? obj::process::current().space()
: vm_space::kernel_space(); : vm_space::kernel_space();
if (cr2 && space.handle_fault(cr2, ft)) if (cr2 && space.handle_fault(cr2, ft))

View File

@@ -86,7 +86,7 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
memcpy(out, buffer, n); memcpy(out, buffer, n);
m_buffer.commit(n); m_buffer.commit(n);
system &sys = system::get(); obj::system &sys = obj::system::get();
sys.assert_signal(j6_signal_system_has_log); sys.assert_signal(j6_signal_system_has_log);
} }

View File

@@ -153,10 +153,11 @@ start_aps(lapic &apic, const util::vector<uint8_t> &ids, void *kpml4)
{ {
using mem::frame_size; using mem::frame_size;
using mem::kernel_stack_pages; using mem::kernel_stack_pages;
using obj::vm_flags;
extern size_t ap_startup_code_size; extern size_t ap_startup_code_size;
extern process &g_kernel_process; extern obj::process &g_kernel_process;
extern vm_area_guarded &g_kernel_stacks; extern obj::vm_area_guarded &g_kernel_stacks;
clock &clk = clock::get(); clock &clk = clock::get();
@@ -173,7 +174,7 @@ start_aps(lapic &apic, const util::vector<uint8_t> &ids, void *kpml4)
// Copy the startup code somwhere the real mode trampoline can run // Copy the startup code somwhere the real mode trampoline can run
uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses
uint8_t vector = addr >> 12; uint8_t vector = addr >> 12;
vm_area *vma = new vm_area_fixed(addr, 0x1000, vm_flags::write); obj::vm_area *vma = new obj::vm_area_fixed(addr, 0x1000, vm_flags::write);
vm_space::kernel_space().add(addr, vma); vm_space::kernel_space().add(addr, vma);
memcpy( memcpy(
reinterpret_cast<void*>(addr), reinterpret_cast<void*>(addr),

View File

@@ -22,6 +22,8 @@
using bootproto::allocation_register; using bootproto::allocation_register;
using bootproto::section_flags; using bootproto::section_flags;
using obj::vm_flags;
extern "C" void initialize_main_thread(); extern "C" void initialize_main_thread();
extern "C" uintptr_t initialize_main_user_stack(); extern "C" uintptr_t initialize_main_user_stack();
@@ -34,13 +36,13 @@ heap_allocator &g_kernel_heap = __g_kernel_heap_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;
static util::no_construct<vm_area_untracked> __g_kernel_heap_area_storage; static util::no_construct<obj::vm_area_untracked> __g_kernel_heap_area_storage;
vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value; obj::vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value;
static util::no_construct<vm_area_guarded> __g_kernel_stacks_storage; static util::no_construct<obj::vm_area_guarded> __g_kernel_stacks_storage;
vm_area_guarded &g_kernel_stacks = __g_kernel_stacks_storage.value; obj::vm_area_guarded &g_kernel_stacks = __g_kernel_stacks_storage.value;
vm_area_guarded g_kernel_buffers { obj::vm_area_guarded g_kernel_buffers {
mem::buffers_offset, mem::buffers_offset,
mem::kernel_buffer_pages, mem::kernel_buffer_pages,
mem::buffers_size, mem::buffers_size,
@@ -81,15 +83,15 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
reg = reg->next; reg = reg->next;
} }
process *kp = process::create_kernel_process(kpml4); obj::process *kp = obj::process::create_kernel_process(kpml4);
vm_space &vm = kp->space(); vm_space &vm = kp->space();
vm_area *heap = new (&g_kernel_heap_area) obj::vm_area *heap = new (&g_kernel_heap_area)
vm_area_untracked(mem::heap_size, vm_flags::write); obj::vm_area_untracked(mem::heap_size, vm_flags::write);
vm.add(mem::heap_offset, heap); vm.add(mem::heap_offset, heap);
vm_area *stacks = new (&g_kernel_stacks) 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,
mem::stacks_size, mem::stacks_size,
@@ -171,8 +173,8 @@ log_mtrrs()
void void
load_init_server(bootproto::program &program, uintptr_t modules_address) load_init_server(bootproto::program &program, uintptr_t modules_address)
{ {
process *p = new process; obj::process *p = new obj::process;
p->add_handle(&system::get()); p->add_handle(&obj::system::get(), obj::system::init_caps);
vm_space &space = p->space(); vm_space &space = p->space();
for (const auto &sect : program.sections) { for (const auto &sect : program.sections) {
@@ -180,15 +182,15 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
((sect.type && section_flags::execute) ? vm_flags::exec : vm_flags::none) | ((sect.type && section_flags::execute) ? vm_flags::exec : vm_flags::none) |
((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none); ((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none);
vm_area *vma = new vm_area_fixed(sect.phys_addr, sect.size, flags); obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags);
space.add(sect.virt_addr, vma); space.add(sect.virt_addr, vma);
} }
uint64_t iopl = (3ull << 12); uint64_t iopl = (3ull << 12);
thread *main = p->create_thread(); obj::thread *main = p->create_thread();
main->add_thunk_user(program.entrypoint, 0, iopl); main->add_thunk_user(program.entrypoint, 0, iopl);
main->set_state(thread::state::ready); main->set_state(obj::thread::state::ready);
// Hacky: No process exists to have created a stack for init; it needs to create // Hacky: No process exists to have created a stack for init; it needs to create
// its own stack. We take advantage of that to use rsp to pass it the init modules // its own stack. We take advantage of that to use rsp to pass it the init modules

View File

@@ -5,7 +5,9 @@
#include "objects/channel.h" #include "objects/channel.h"
#include "objects/vm_area.h" #include "objects/vm_area.h"
extern vm_area_guarded g_kernel_buffers; extern obj::vm_area_guarded g_kernel_buffers;
namespace obj {
constexpr size_t buffer_bytes = mem::kernel_buffer_pages * mem::frame_size; constexpr size_t buffer_bytes = mem::kernel_buffer_pages * mem::frame_size;
@@ -89,3 +91,5 @@ channel::on_no_handles()
kobject::on_no_handles(); kobject::on_no_handles();
delete this; delete this;
} }
} // namespace obj

View File

@@ -7,11 +7,16 @@
#include "objects/kobject.h" #include "objects/kobject.h"
namespace obj {
/// Channels are bi-directional means of sending messages /// Channels are bi-directional means of sending messages
class channel : class channel :
public kobject public kobject
{ {
public: public:
/// Capabilities on a newly constructed channel handle
constexpr static j6_cap_t creation_caps = 0;
channel(); channel();
virtual ~channel(); virtual ~channel();
@@ -48,3 +53,5 @@ private:
uintptr_t m_data; uintptr_t m_data;
util::bip_buffer m_buffer; util::bip_buffer m_buffer;
}; };
} // namespace obj

View File

@@ -5,6 +5,8 @@
#include "objects/thread.h" #include "objects/thread.h"
#include "vm_space.h" #include "vm_space.h"
namespace obj {
endpoint::endpoint() : endpoint::endpoint() :
kobject {kobject::type::endpoint} kobject {kobject::type::endpoint}
{} {}
@@ -135,3 +137,5 @@ endpoint::do_message_copy(const endpoint::thread_data &sender, endpoint::thread_
return j6_status_ok; return j6_status_ok;
} }
} // namespace obj

View File

@@ -7,11 +7,16 @@
#include "objects/kobject.h" #include "objects/kobject.h"
namespace obj {
/// Endpoints are objects that enable synchronous message-passing IPC /// Endpoints are objects that enable synchronous message-passing IPC
class endpoint : class endpoint :
public kobject public kobject
{ {
public: public:
/// Capabilities on a newly constructed endpoint handle
constexpr static j6_cap_t creation_caps = 0;
endpoint(); endpoint();
virtual ~endpoint(); virtual ~endpoint();
@@ -69,3 +74,5 @@ private:
util::vector<thread_data> m_blocked; util::vector<thread_data> m_blocked;
}; };
} // namespace obj

View File

@@ -4,12 +4,19 @@
#include "objects/kobject.h" #include "objects/kobject.h"
namespace obj {
class event : class event :
public kobject public kobject
{ {
public: public:
/// Capabilities on a newly constructed event handle
constexpr static j6_cap_t creation_caps = 0;
event() : event() :
kobject(type::event) {} kobject(type::event) {}
static constexpr kobject::type type = kobject::type::event; static constexpr kobject::type type = kobject::type::event;
}; };
} // namespace obj

View File

@@ -0,0 +1,82 @@
#pragma once
/// \file handle.h
/// Definition of kobject handles
#include <j6/types.h>
#include "objects/kobject.h"
namespace obj {
struct handle
{
inline handle(j6_handle_t in_id, kobject *in_object, j6_cap_t in_caps) :
id {in_id}, object {in_object}, caps {in_caps} {
if (object) object->handle_retain();
}
inline handle(const handle &other) :
id {other.id}, object {other.object}, caps {other.caps} {
if (object) object->handle_retain();
}
inline handle(handle &&other) :
id {other.id}, object {other.object}, caps {other.caps} {
other.id = 0;
other.caps = 0;
other.object = nullptr;
}
inline handle & operator=(const handle &other) {
if (object) object->handle_release();
id = other.id; caps = other.caps; object = other.object;
if (object) object->handle_retain();
return *this;
}
inline handle & operator=(handle &&other) {
if (object) object->handle_release();
id = other.id; caps = other.caps; object = other.object;
other.id = other.caps = 0; other.object = nullptr;
return *this;
}
inline ~handle() {
if (object) object->handle_release();
}
inline bool has_cap(j6_cap_t test) const {
return (caps & test) == test;
}
inline kobject::type type() const {
return object->get_type();
}
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;
j6_cap_t caps;
kobject *object;
};
} // namespace obj

View File

@@ -6,7 +6,8 @@
#include "objects/kobject.h" #include "objects/kobject.h"
#include "objects/thread.h" #include "objects/thread.h"
// TODO: per-cpu this? namespace obj {
static j6_koid_t next_koids [static_cast<size_t>(kobject::type::max)] = { 0 }; static j6_koid_t next_koids [static_cast<size_t>(kobject::type::max)] = { 0 };
kobject::kobject(type t, j6_signal_t signals) : kobject::kobject(type t, j6_signal_t signals) :
@@ -26,7 +27,8 @@ kobject::koid_generate(type t)
{ {
kassert(t < type::max, "Object type out of bounds"); kassert(t < type::max, "Object type out of bounds");
uint64_t type_int = static_cast<uint64_t>(t); uint64_t type_int = static_cast<uint64_t>(t);
return (type_int << 48) | next_koids[type_int]++; uint64_t id = __atomic_fetch_add(&next_koids[type_int], 1, __ATOMIC_SEQ_CST);
return (type_int << 48) | id;
} }
kobject::type kobject::type
@@ -74,3 +76,5 @@ kobject::on_no_handles()
{ {
assert_signal(j6_signal_no_handles); assert_signal(j6_signal_no_handles);
} }
} // namespace obj

View File

@@ -7,6 +7,8 @@
#include <j6/types.h> #include <j6/types.h>
#include <util/vector.h> #include <util/vector.h>
namespace obj {
class thread; class thread;
/// Base type for all user-interactable kernel objects /// Base type for all user-interactable kernel objects
@@ -98,3 +100,5 @@ private:
protected: protected:
util::vector<thread*> m_blocked_threads; util::vector<thread*> m_blocked_threads;
}; };
} // namespace obj

View File

@@ -7,19 +7,22 @@
#include "objects/vm_area.h" #include "objects/vm_area.h"
#include "scheduler.h" #include "scheduler.h"
// This object is initialized _before_ global constructors are called, // This object is initialized _before_ global constructors are called,
// so we don't want it to have a global constructor at all, lest it // so we don't want it to have a global constructor at all, lest it
// overwrite the previous initialization. // overwrite the previous initialization.
static util::no_construct<process> __g_kernel_process_storage; static util::no_construct<obj::process> __g_kernel_process_storage;
process &g_kernel_process = __g_kernel_process_storage.value; obj::process &g_kernel_process = __g_kernel_process_storage.value;
namespace obj {
process::process() : process::process() :
kobject {kobject::type::process}, kobject {kobject::type::process},
m_next_handle {1}, m_next_handle {1},
m_state {state::running} m_state {state::running}
{ {
j6_handle_t self = add_handle(this); j6_handle_t self = add_handle(this, process::self_caps);
kassert(self == self_handle(), "Process self-handle is not 1"); kassert(self == self_handle(), "Process self-handle is not 1");
} }
@@ -34,8 +37,6 @@ process::process(page_table *kpml4) :
process::~process() process::~process()
{ {
for (auto &it : m_handles)
if (it.val) it.val->handle_release();
} }
process & process::current() { return *current_cpu().process; } process & process::current() { return *current_cpu().process; }
@@ -123,27 +124,27 @@ process::thread_exited(thread *th)
} }
j6_handle_t j6_handle_t
process::add_handle(kobject *obj) process::add_handle(kobject *obj, j6_cap_t caps)
{ {
if (!obj) if (!obj)
return j6_handle_invalid; return j6_handle_invalid;
obj->handle_retain(); j6_handle_t id = m_next_handle++;
j6_handle_t handle = m_next_handle++; m_handles.insert(id, {id, obj, caps});
m_handles.insert(handle, obj);
return handle; return id;
} }
bool bool
process::remove_handle(j6_handle_t handle) process::remove_handle(j6_handle_t id)
{ {
kobject *obj = m_handles.find(handle); return m_handles.erase(id);
if (obj) obj->handle_release();
return m_handles.erase(handle);
} }
kobject * handle *
process::lookup_handle(j6_handle_t handle) process::lookup_handle(j6_handle_t id)
{ {
return m_handles.find(handle); return m_handles.find(id);
} }
} // namespace obj

View File

@@ -5,14 +5,23 @@
#include <util/map.h> #include <util/map.h>
#include <util/vector.h> #include <util/vector.h>
#include "objects/handle.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"
namespace obj {
class process : class process :
public kobject public kobject
{ {
public: public:
/// Capabilities on a newly constructed process handle
constexpr static j6_cap_t creation_caps = 0;
/// Capabilities on a process to itself
constexpr static j6_cap_t self_caps = 0;
/// Top of memory area where thread stacks are allocated /// Top of memory area where thread stacks are allocated
constexpr static uintptr_t stacks_top = 0x0000800000000000; constexpr static uintptr_t stacks_top = 0x0000800000000000;
@@ -51,8 +60,9 @@ public:
/// Start tracking an object with a handle. /// Start tracking an object with a handle.
/// \args obj The object this handle refers to /// \args obj The object this handle refers to
/// \args caps The capabilities on this handle
/// \returns The new handle for this object /// \returns The new handle for this object
j6_handle_t add_handle(kobject *obj); j6_handle_t add_handle(kobject *obj, j6_cap_t caps);
/// Stop tracking an object with a handle. /// 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
@@ -61,8 +71,8 @@ public:
/// Lookup an object for a handle /// Lookup an object for a handle
/// \args handle The handle to the object /// \args handle The handle to the object
/// \returns Pointer to the object, or null if not found /// \returns Pointer to the handle struct, or null if not found
kobject * lookup_handle(j6_handle_t handle); handle * lookup_handle(j6_handle_t handle);
/// 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
@@ -90,9 +100,12 @@ private:
vm_space m_space; vm_space m_space;
util::vector<thread*> m_threads; util::vector<thread*> m_threads;
util::map<j6_handle_t, kobject*> m_handles;
j6_handle_t m_next_handle; j6_handle_t m_next_handle;
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;
}; };
} // namespace obj

View File

@@ -1,3 +1,7 @@
#include "objects/system.h" #include "objects/system.h"
namespace obj {
system system::s_instance; system system::s_instance;
} // namespace obj

View File

@@ -4,11 +4,16 @@
#include "objects/kobject.h" #include "objects/kobject.h"
namespace obj {
class system : class system :
public kobject public kobject
{ {
public: public:
static constexpr kobject::type type = kobject::type::event; /// Capabilities on system given to init
constexpr static j6_cap_t init_caps = 0;
static constexpr kobject::type type = kobject::type::system;
inline static system & get() { return s_instance; } inline static system & get() { return s_instance; }
@@ -16,3 +21,5 @@ private:
static system s_instance; static system s_instance;
system() : kobject(type::system) {} system() : kobject(type::system) {}
}; };
} // namespace obj

View File

@@ -10,9 +10,12 @@
#include "scheduler.h" #include "scheduler.h"
extern "C" void kernel_to_user_trampoline(); extern "C" void kernel_to_user_trampoline();
static constexpr j6_signal_t thread_default_signals = 0; extern obj::vm_area_guarded &g_kernel_stacks;
extern vm_area_guarded &g_kernel_stacks;
namespace obj {
static constexpr j6_signal_t thread_default_signals = 0;
thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) : thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
kobject(kobject::type::thread, thread_default_signals), kobject(kobject::type::thread, thread_default_signals),
@@ -32,7 +35,7 @@ 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); m_self_handle = parent.add_handle(this, thread::parent_caps);
} }
thread::~thread() thread::~thread()
@@ -246,3 +249,5 @@ thread::create_idle_thread(process &kernel, uint8_t pri, uintptr_t rsp0)
idle->set_state(state::ready); idle->set_state(state::ready);
return idle; return idle;
} }
} // namespace obj

View File

@@ -9,7 +9,10 @@
#include "objects/kobject.h" #include "objects/kobject.h"
struct page_table; struct page_table;
class process;
namespace obj {
class thread;
}
struct TCB struct TCB
{ {
@@ -22,7 +25,7 @@ struct TCB
uintptr_t pml4; uintptr_t pml4;
// End of area used by asembly // End of area used by asembly
thread* thread; obj::thread* thread;
uint8_t priority; uint8_t priority;
// note: 3 bytes padding // note: 3 bytes padding
@@ -38,6 +41,9 @@ struct TCB
using tcb_list = util::linked_list<TCB>; using tcb_list = util::linked_list<TCB>;
using tcb_node = tcb_list::item_type; using tcb_node = tcb_list::item_type;
namespace obj {
enum class wait_type : uint8_t enum class wait_type : uint8_t
{ {
none = 0x00, none = 0x00,
@@ -47,10 +53,17 @@ enum class wait_type : uint8_t
}; };
is_bitfield(wait_type); is_bitfield(wait_type);
class process;
class thread : class thread :
public kobject public kobject
{ {
public: public:
/// Capabilities on a newly constructed thread handle
constexpr static j6_cap_t creation_caps = 0;
/// Capabilities the parent process gets on new thread handles
constexpr static j6_cap_t parent_caps = 0;
enum class state : uint8_t { enum class state : uint8_t {
ready = 0x01, ready = 0x01,
@@ -203,3 +216,5 @@ private:
j6_handle_t m_self_handle; j6_handle_t m_self_handle;
}; };
} // namespace obj

View File

@@ -6,6 +6,8 @@
#include "page_tree.h" #include "page_tree.h"
#include "vm_space.h" #include "vm_space.h"
namespace obj {
using mem::frame_size; using mem::frame_size;
vm_area::vm_area(size_t size, vm_flags flags) : vm_area::vm_area(size_t size, vm_flags flags) :
@@ -184,3 +186,5 @@ vm_area_guarded::get_page(uintptr_t offset, uintptr_t &phys)
return vm_area_open::get_page(offset, phys); return vm_area_open::get_page(offset, phys);
} }
} // namespace obj

View File

@@ -14,6 +14,9 @@
class page_tree; class page_tree;
class vm_space; class vm_space;
namespace obj {
enum class vm_flags : uint32_t enum class vm_flags : uint32_t
{ {
#define VM_FLAG(name, v) name = v, #define VM_FLAG(name, v) name = v,
@@ -22,6 +25,7 @@ enum class vm_flags : uint32_t
driver_mask = 0x000fffff, ///< flags allowed via syscall for drivers driver_mask = 0x000fffff, ///< flags allowed via syscall for drivers
user_mask = 0x0000ffff, ///< flags allowed via syscall for non-drivers user_mask = 0x0000ffff, ///< flags allowed via syscall for non-drivers
}; };
is_bitfield(vm_flags);
/// Virtual memory areas allow control over memory allocation /// Virtual memory areas allow control over memory allocation
@@ -29,6 +33,9 @@ class vm_area :
public kobject public kobject
{ {
public: public:
/// Capabilities on a newly constructed vma handle
constexpr static j6_cap_t creation_caps = 0;
static constexpr kobject::type type = kobject::type::vma; static constexpr kobject::type type = kobject::type::vma;
/// Constructor. /// Constructor.
@@ -170,5 +177,4 @@ private:
uintptr_t m_next; uintptr_t m_next;
}; };
} // namespace obj
is_bitfield(vm_flags);

View File

@@ -20,6 +20,8 @@
#include "objects/vm_area.h" #include "objects/vm_area.h"
#include "scheduler.h" #include "scheduler.h"
using obj::process;
using obj::thread;
extern "C" void task_switch(TCB *tcb); extern "C" void task_switch(TCB *tcb);
scheduler *scheduler::s_instance = nullptr; scheduler *scheduler::s_instance = nullptr;

View File

@@ -12,10 +12,13 @@ namespace args {
struct cpu_data; struct cpu_data;
class lapic; class lapic;
class process;
struct page_table; struct page_table;
struct run_queue; struct run_queue;
namespace obj {
class process;
class thread;
}
/// The task scheduler /// The task scheduler
class scheduler class scheduler
@@ -47,7 +50,7 @@ public:
/// Create a new process from a program image in memory. /// Create a new process from a program image in memory.
/// \arg program The descriptor of the pogram in memory /// \arg program The descriptor of the pogram in memory
/// \returns The main thread of the loaded process /// \returns The main thread of the loaded process
thread * load_process(kernel::args::program &program); obj::thread * load_process(kernel::args::program &program);
/// Create a new kernel task /// Create a new kernel task
/// \arg proc Function to run as a kernel task /// \arg proc Function to run as a kernel task
@@ -77,7 +80,7 @@ public:
static scheduler & get() { return *s_instance; } static scheduler & get() { return *s_instance; }
private: private:
friend class process; friend class obj::process;
static constexpr uint64_t promote_frequency = 10; static constexpr uint64_t promote_frequency = 10;
static constexpr uint64_t steal_frequency = 10; static constexpr uint64_t steal_frequency = 10;
@@ -89,7 +92,7 @@ private:
uint32_t m_next_pid; uint32_t m_next_pid;
uint32_t m_tick_count; uint32_t m_tick_count;
process *m_kernel_process; obj::process *m_kernel_process;
util::vector<run_queue> m_run_queues; util::vector<run_queue> m_run_queues;

View File

@@ -41,9 +41,9 @@ namespace syscalls
args = [] args = []
if method.constructor: if method.constructor:
args.append("j6_handle_t *handle") args.append("j6_handle_t *self")
elif not method.static: elif not method.static:
args.append("j6_handle_t handle") args.append("j6_handle_t self")
for param in method.params: for param in method.params:
for type, suffix in param.type.c_names(param.options): for type, suffix in param.type.c_names(param.options):

View File

@@ -4,6 +4,21 @@
#include <arch/memory.h> #include <arch/memory.h>
#include <j6/errors.h> #include <j6/errors.h>
#include <j6/types.h> #include <j6/types.h>
#include <util/counted.h>
#include "syscalls/helpers.h"
/*[[[cog code generation
from definitions.context import Context
ctx = Context(definitions_path)
ctx.parse("syscalls.def")
syscalls = ctx.interfaces["syscalls"]
for obj in syscalls.exposes:
cog.outl(f'#include "objects/{obj.object.cname}.h"')
]]]*/
//[[[end]]]
namespace { namespace {
template <typename T> template <typename T>
@@ -16,13 +31,9 @@ namespace {
namespace syscalls { namespace syscalls {
using util::buffer;
/*[[[cog code generation /*[[[cog code generation
from definitions.context import Context
ctx = Context(definitions_path)
ctx.parse("syscalls.def")
syscalls = ctx.interfaces["syscalls"]
cbool = {True: "true", False: "false"} cbool = {True: "true", False: "false"}
for id, scope, method in syscalls.methods: for id, scope, method in syscalls.methods:
@@ -33,22 +44,41 @@ for id, scope, method in syscalls.methods:
args = [] args = []
argdefs = [] argdefs = []
cxxargdefs = []
refparams = [] refparams = []
handles = []
if method.constructor: if method.constructor:
argdefs.append("j6_handle_t *handle") argdefs.append("j6_handle_t *self")
args.append("handle") cxxargdefs.append("j6_handle_t *self")
refparams.append(("handle", False)) args.append("self")
refparams.append(("self", False))
elif not method.static: elif not method.static:
argdefs.append("j6_handle_t handle") argdefs.append("j6_handle_t self")
args.append("handle") cxxargdefs.append(f"obj::{scope.cname} *self")
args.append("self_obj")
handles.append((f"obj::{scope.cname} *", "self", "self_obj"))
for param in method.params: for param in method.params:
needs_obj = param.type.needs_object(param.options)
for type, suffix in param.type.c_names(param.options): for type, suffix in param.type.c_names(param.options):
arg = f"{param.name}{suffix}" arg = f"{param.name}{suffix}"
argdefs.append(f"{type} {arg}") argdefs.append(f"{type} {arg}")
for type, suffix in param.type.cxx_names(param.options):
arg = f"{param.name}{suffix}"
cxxargdefs.append(f"{type} {arg}")
if needs_obj:
oarg = f"{arg}_obj"
handles.append((type, arg, oarg))
args.append(oarg)
else:
args.append(arg) args.append(arg)
if param.refparam: if param.refparam:
subs = param.type.c_names(param.options) subs = param.type.c_names(param.options)
refparams.append((param.name + subs[0][1], param.optional)) refparams.append((param.name + subs[0][1], param.optional))
@@ -56,7 +86,7 @@ for id, scope, method in syscalls.methods:
for sub in subs[1:]: for sub in subs[1:]:
refparams.append((param.name + sub[1], param.optional)) refparams.append((param.name + sub[1], param.optional))
cog.outl(f"""extern j6_status_t {name} ({", ".join(argdefs)});""") cog.outl(f"""j6_status_t {name} ({", ".join(cxxargdefs)});""")
cog.outl(f"""j6_status_t _syscall_verify_{name} ({", ".join(argdefs)}) {{""") cog.outl(f"""j6_status_t _syscall_verify_{name} ({", ".join(argdefs)}) {{""")
for pname, optional in refparams: for pname, optional in refparams:
@@ -64,7 +94,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()
cog.outl(f""" return syscalls::{name}({", ".join(args)});""") for type, inarg, outarg in handles:
if type.endswith('*'):
type = type[:-1].strip()
cog.outl(f" obj::handle *{inarg}_handle = get_handle<typename {type}>({inarg});")
cog.outl(f" if (!{inarg}_handle) return j6_err_invalid_arg;")
cog.outl(f" {type} *{outarg} = {inarg}_handle->as<typename {type}>();")
cog.outl(f" if (!{outarg}) return j6_err_invalid_arg;")
cog.outl()
cog.outl(f""" return {name}({", ".join(args)});""")
cog.outl("}") cog.outl("}")
cog.outl("\n") cog.outl("\n")
]]]*/ ]]]*/

View File

@@ -4,29 +4,27 @@
#include "objects/channel.h" #include "objects/channel.h"
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
using namespace obj;
namespace syscalls { namespace syscalls {
j6_status_t j6_status_t
channel_create(j6_handle_t *handle) channel_create(j6_handle_t *self)
{ {
construct_handle<channel>(handle); construct_handle<channel>(self);
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
channel_send(j6_handle_t handle, size_t *len, void *data) channel_send(channel *self, size_t *len, void *data)
{ {
channel *c = get_handle<channel>(handle); return self->enqueue(len, data);
if (!c) return j6_err_invalid_arg;
return c->enqueue(len, data);
} }
j6_status_t j6_status_t
channel_receive(j6_handle_t handle, size_t *len, void *data) channel_receive(channel *self, size_t *len, void *data)
{ {
channel *c = get_handle<channel>(handle); return self->dequeue(len, data);
if (!c) return j6_err_invalid_arg;
return c->dequeue(len, data);
} }
} // namespace syscalls } // namespace syscalls

View File

@@ -5,62 +5,61 @@
#include "objects/endpoint.h" #include "objects/endpoint.h"
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
using namespace obj;
namespace syscalls { namespace syscalls {
j6_status_t j6_status_t
endpoint_create(j6_handle_t *handle) endpoint_create(j6_handle_t *self)
{ {
construct_handle<endpoint>(handle); construct_handle<endpoint>(self);
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
endpoint_send(j6_handle_t handle, uint64_t tag, const void * data, size_t data_len) endpoint_send(endpoint *self, uint64_t tag, const void * data, size_t data_len)
{ {
if (tag & j6_tag_system_flag) if (tag & j6_tag_system_flag)
return j6_err_invalid_arg; return j6_err_invalid_arg;
endpoint *e = get_handle<endpoint>(handle); return self->send(tag, data, data_len);
if (!e) return j6_err_invalid_arg;
return e->send(tag, data, data_len);
} }
j6_status_t j6_status_t
endpoint_receive(j6_handle_t handle, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout) endpoint_receive(endpoint *self, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout)
{ {
// Data is marked optional, but we need the length, and if length > 0, // Data is marked optional, but we need the length, and if length > 0,
// data is not optional. // data is not optional.
if (!data_len || (*data_len && !data)) if (!data_len || (*data_len && !data))
return j6_err_invalid_arg; return j6_err_invalid_arg;
endpoint *e = get_handle<endpoint>(handle); // Use local variables instead of the passed-in pointers, since
if (!e) return j6_err_invalid_arg; // they may get filled in when the sender is running, which means
// a different user VM space would be active.
j6_tag_t out_tag = j6_tag_invalid; j6_tag_t out_tag = j6_tag_invalid;
size_t out_len = *data_len; size_t out_len = *data_len;
j6_status_t s = e->receive(&out_tag, data, &out_len, timeout); j6_status_t s = self->receive(&out_tag, data, &out_len, timeout);
*tag = out_tag; *tag = out_tag;
*data_len = out_len; *data_len = out_len;
return s; return s;
} }
j6_status_t j6_status_t
endpoint_sendrecv(j6_handle_t handle, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout) endpoint_sendrecv(endpoint *self, uint64_t * tag, void * data, size_t * data_len, uint64_t timeout)
{ {
if (*tag & j6_tag_system_flag) if (*tag & j6_tag_system_flag)
return j6_err_invalid_arg; return j6_err_invalid_arg;
endpoint *e = get_handle<endpoint>(handle); j6_status_t status = self->send(*tag, data, *data_len);
if (!e) return j6_err_invalid_arg;
j6_status_t status = e->send(*tag, data, *data_len);
if (status != j6_status_ok) if (status != j6_status_ok)
return status; return status;
// Use local variables instead of the passed-in pointers, since
// they may get filled in when the sender is running, which means
// a different user VM space would be active.
j6_tag_t out_tag = j6_tag_invalid; j6_tag_t out_tag = j6_tag_invalid;
size_t out_len = *data_len; size_t out_len = *data_len;
j6_status_t s = e->receive(&out_tag, data, &out_len, timeout); j6_status_t s = self->receive(&out_tag, data, &out_len, timeout);
*tag = out_tag; *tag = out_tag;
*data_len = out_len; *data_len = out_len;
return s; return s;

View File

@@ -10,38 +10,41 @@
namespace syscalls { namespace syscalls {
template <typename T, typename... Args> template <typename T, typename... Args>
T * construct_handle(j6_handle_t *handle, Args... args) T * construct_handle(j6_handle_t *id, Args... args)
{ {
process &p = process::current(); obj::process &p = obj::process::current();
T *o = new T {args...}; T *o = new T {args...};
*handle = p.add_handle(o); *id = p.add_handle(o, T::creation_caps);
return o; return o;
} }
template <typename T> template <typename T>
T * get_handle(j6_handle_t handle) obj::handle * get_handle(j6_handle_t id)
{ {
process &p = process::current(); obj::process &p = obj::process::current();
kobject *o = p.lookup_handle(handle); obj::handle *h = p.lookup_handle(id);
if (!o || o->get_type() != T::type) if (!h || h->type() != T::type)
return nullptr; return nullptr;
return static_cast<T*>(o); return h;
} }
template <> template <>
inline kobject * get_handle<kobject>(j6_handle_t handle) inline obj::handle * get_handle<obj::kobject>(j6_handle_t id)
{ {
process &p = process::current(); obj::process &p = obj::process::current();
return p.lookup_handle(handle); return p.lookup_handle(id);
} }
template <typename T> template <typename T>
T * remove_handle(j6_handle_t handle) T * remove_handle(j6_handle_t id)
{ {
T *o = get_handle<T>(handle); obj::handle *h = get_handle<T>(id);
if (o) { T *o = nullptr;
process &p = process::current();
p.remove_handle(handle); if (h) {
o = h->object;
obj::process &p = obj::process::current();
p.remove_handle(id);
} }
return o; return o;
} }

View File

@@ -8,34 +8,28 @@
#include "objects/thread.h" #include "objects/thread.h"
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
using namespace obj;
namespace syscalls { namespace syscalls {
j6_status_t j6_status_t
kobject_koid(j6_handle_t handle, j6_koid_t *koid) kobject_koid(kobject *self, j6_koid_t *koid)
{ {
kobject *obj = get_handle<kobject>(handle); *koid = self->koid();
if (!obj)
return j6_err_invalid_arg;
*koid = obj->koid();
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
kobject_wait(j6_handle_t handle, j6_signal_t mask, j6_signal_t *sigs) kobject_wait(kobject *self, j6_signal_t mask, j6_signal_t *sigs)
{ {
kobject *obj = get_handle<kobject>(handle); j6_signal_t current = self->signals();
if (!obj)
return j6_err_invalid_arg;
j6_signal_t current = obj->signals();
if ((current & mask) != 0) { if ((current & mask) != 0) {
*sigs = current; *sigs = current;
return j6_status_ok; return j6_status_ok;
} }
thread &th = thread::current(); thread &th = thread::current();
obj->add_blocked_thread(&th); self->add_blocked_thread(&th);
th.wait_on_signals(mask); th.wait_on_signals(mask);
j6_status_t result = th.get_wait_result(); j6_status_t result = th.get_wait_result();
@@ -46,23 +40,24 @@ kobject_wait(j6_handle_t handle, j6_signal_t mask, j6_signal_t *sigs)
} }
j6_status_t j6_status_t
kobject_wait_many(j6_handle_t * handles, size_t handles_count, uint64_t mask, j6_handle_t * handle, uint64_t * signals) kobject_wait_many(j6_handle_t * handles, size_t handles_count, uint64_t mask, j6_handle_t * woken, uint64_t * signals)
{ {
util::vector<kobject*> objects {uint32_t(handles_count)}; util::vector<kobject*> objects {uint32_t(handles_count)};
for (unsigned i = 0; i < handles_count; ++i) { for (unsigned i = 0; i < handles_count; ++i) {
j6_handle_t h = handles[i]; j6_handle_t hid = handles[i];
if (h == j6_handle_invalid) if (hid == j6_handle_invalid)
continue; continue;
kobject *obj = get_handle<kobject>(h); handle *h = get_handle<kobject>(hid);
if (!obj) if (!h || !h->object)
return j6_err_invalid_arg; return j6_err_invalid_arg;
kobject *obj = h->object;
j6_signal_t current = obj->signals(); j6_signal_t current = obj->signals();
if ((current & mask) != 0) { if ((current & mask) != 0) {
*signals = current; *signals = current;
*handle = h; *woken = hid;
return j6_status_ok; return j6_status_ok;
} }
@@ -79,43 +74,35 @@ kobject_wait_many(j6_handle_t * handles, size_t handles_count, uint64_t mask, j6
if (result != j6_status_ok) if (result != j6_status_ok)
return result; return result;
*handle = j6_handle_invalid; *woken = j6_handle_invalid;
*signals = th.get_wait_data(); *signals = th.get_wait_data();
j6_koid_t koid = th.get_wait_object(); j6_koid_t koid = th.get_wait_object();
for (unsigned i = 0; i < handles_count; ++i) { for (unsigned i = 0; i < handles_count; ++i) {
if (koid == objects[i]->koid()) if (koid == objects[i]->koid())
*handle = handles[i]; *woken = handles[i];
else else
objects[i]->remove_blocked_thread(&th); objects[i]->remove_blocked_thread(&th);
} }
kassert(*handle != j6_handle_invalid, kassert(*woken != j6_handle_invalid,
"Somehow woke on a handle that was not waited on"); "Somehow woke on a handle that was not waited on");
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
kobject_signal(j6_handle_t handle, j6_signal_t signals) kobject_signal(kobject *self, j6_signal_t signals)
{ {
if ((signals & j6_signal_user_mask) != signals) if ((signals & j6_signal_user_mask) != signals)
return j6_err_invalid_arg; return j6_err_invalid_arg;
kobject *obj = get_handle<kobject>(handle); self->assert_signal(signals);
if (!obj)
return j6_err_invalid_arg;
obj->assert_signal(signals);
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
kobject_close(j6_handle_t handle) kobject_close(kobject *self)
{ {
kobject *obj = get_handle<kobject>(handle); self->close();
if (!obj)
return j6_err_invalid_arg;
obj->close();
return j6_status_ok; return j6_status_ok;
} }

View File

@@ -5,41 +5,25 @@
#include "objects/process.h" #include "objects/process.h"
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
using namespace obj;
namespace syscalls { namespace syscalls {
j6_status_t j6_status_t
process_create(j6_handle_t *handle) process_create(j6_handle_t *self)
{ {
process *child = construct_handle<process>(handle); process *p = construct_handle<process>(self);
log::debug(logs::task, "Process %llx created", child->koid()); log::debug(logs::task, "Process %llx created", p->koid());
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
process_start(j6_handle_t handle, uintptr_t entrypoint, j6_handle_t * handles, size_t handles_count) process_kill(process *self)
{ {
process &p = process::current(); process &p = process::current();
process *c = get_handle<process>(handle);
if (handles_count && !handles)
return j6_err_invalid_arg;
for (size_t i = 0; i < handles_count; ++i) { log::debug(logs::task, "Process %llx killed by process %llx", self->koid(), p.koid());
kobject *o = p.lookup_handle(handles[i]); self->exit(-1u);
if (o) c->add_handle(o);
}
return j6_err_nyi;
}
j6_status_t
process_kill(j6_handle_t handle)
{
process &p = process::current();
process *c = get_handle<process>(handle);
if (!c) return j6_err_invalid_arg;
log::debug(logs::task, "Process %llx killed by process %llx", c->koid(), p.koid());
c->exit(-1u);
return j6_status_ok; return j6_status_ok;
} }
@@ -57,16 +41,13 @@ process_exit(int32_t status)
} }
j6_status_t j6_status_t
process_give_handle(j6_handle_t handle, j6_handle_t sender, j6_handle_t *receiver) process_give_handle(process *self, j6_handle_t target, j6_handle_t *received)
{ {
process *dest = get_handle<process>(handle); handle *target_handle = get_handle<kobject>(target);
if (!dest) return j6_err_invalid_arg; j6_handle_t out = self->add_handle(target_handle->object, target_handle->caps);
kobject *o = get_handle<kobject>(sender); if (received)
j6_handle_t out = dest->add_handle(o); *received = out;
if (receiver)
*receiver = out;
return j6_status_ok; return j6_status_ok;
} }

View File

@@ -14,8 +14,12 @@
extern log::logger &g_logger; extern log::logger &g_logger;
using namespace obj;
namespace syscalls { namespace syscalls {
using system = class ::system;
j6_status_t j6_status_t
log(const char *message) log(const char *message)
{ {
@@ -33,7 +37,7 @@ noop()
} }
j6_status_t j6_status_t
system_get_log(j6_handle_t sys, void *buffer, size_t *buffer_len) system_get_log(system *self, void *buffer, size_t *buffer_len)
{ {
// Buffer is marked optional, but we need the length, and if length > 0, // Buffer is marked optional, but we need the length, and if length > 0,
// buffer is not optional. // buffer is not optional.
@@ -43,25 +47,22 @@ system_get_log(j6_handle_t sys, void *buffer, size_t *buffer_len)
size_t orig_size = *buffer_len; size_t orig_size = *buffer_len;
*buffer_len = g_logger.get_entry(buffer, *buffer_len); *buffer_len = g_logger.get_entry(buffer, *buffer_len);
if (!g_logger.has_log()) if (!g_logger.has_log())
system::get().deassert_signal(j6_signal_system_has_log); self->deassert_signal(j6_signal_system_has_log);
return (*buffer_len > orig_size) ? j6_err_insufficient : j6_status_ok; return (*buffer_len > orig_size) ? j6_err_insufficient : j6_status_ok;
} }
j6_status_t j6_status_t
system_bind_irq(j6_handle_t sys, j6_handle_t endp, unsigned irq) system_bind_irq(system *self, endpoint *endp, unsigned irq)
{ {
endpoint *e = get_handle<endpoint>(endp); if (device_manager::get().bind_irq(irq, endp))
if (!e) return j6_err_invalid_arg;
if (device_manager::get().bind_irq(irq, e))
return j6_status_ok; return j6_status_ok;
return j6_err_invalid_arg; return j6_err_invalid_arg;
} }
j6_status_t j6_status_t
system_map_phys(j6_handle_t handle, j6_handle_t * area, uintptr_t phys, size_t size, uint32_t flags) system_map_phys(system *self, j6_handle_t * area, uintptr_t phys, size_t size, uint32_t flags)
{ {
// TODO: check to see if frames are already used? How would that collide with // TODO: check to see if frames are already used? How would that collide with
// the bootloader's allocated pages already being marked used? // the bootloader's allocated pages already being marked used?
@@ -75,7 +76,7 @@ system_map_phys(j6_handle_t handle, j6_handle_t * area, uintptr_t phys, size_t s
} }
j6_status_t j6_status_t
system_request_iopl(j6_handle_t handle, unsigned iopl) system_request_iopl(system *self, unsigned iopl)
{ {
if (iopl != 0 && iopl != 3) if (iopl != 0 && iopl != 3)
return j6_err_invalid_arg; return j6_err_invalid_arg;

View File

@@ -6,25 +6,24 @@
#include "objects/thread.h" #include "objects/thread.h"
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
using namespace obj;
namespace syscalls { namespace syscalls {
j6_status_t j6_status_t
thread_create(j6_handle_t *handle, j6_handle_t proc, uintptr_t stack_top, uintptr_t entrypoint) thread_create(j6_handle_t *self, process *proc, uintptr_t stack_top, uintptr_t entrypoint)
{ {
thread &parent_th = thread::current(); thread &parent_th = thread::current();
process &parent_pr = parent_th.parent(); process &parent_pr = parent_th.parent();
process *owner = get_handle<process>(proc); thread *child = proc->create_thread(stack_top);
if (!owner) return j6_err_invalid_arg;
thread *child = owner->create_thread(stack_top);
child->add_thunk_user(entrypoint); child->add_thunk_user(entrypoint);
*handle = child->self_handle(); *self = child->self_handle();
child->clear_state(thread::state::loading); child->clear_state(thread::state::loading);
child->set_state(thread::state::ready); child->set_state(thread::state::ready);
log::debug(logs::task, "Thread %llx:%llx spawned new thread %llx:%llx", log::debug(logs::task, "Thread %llx:%llx spawned new thread %llx:%llx",
parent_pr.koid(), parent_th.koid(), owner->koid(), child->koid()); parent_pr.koid(), parent_th.koid(), proc->koid(), child->koid());
return j6_status_ok; return j6_status_ok;
} }
@@ -41,14 +40,10 @@ thread_exit(int32_t status)
} }
j6_status_t j6_status_t
thread_kill(j6_handle_t handle) thread_kill(thread *self)
{ {
thread *th = get_handle<thread>(handle); log::debug(logs::task, "Killing thread %llx", self->koid());
if (!th) self->exit(-1);
return j6_err_invalid_arg;
log::debug(logs::task, "Killing thread %llx", th->koid());
th->exit(-1);
return j6_status_ok; return j6_status_ok;
} }

View File

@@ -8,58 +8,45 @@
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
#include "vm_space.h" #include "vm_space.h"
using namespace obj;
namespace syscalls { namespace syscalls {
j6_status_t j6_status_t
vma_create(j6_handle_t *handle, size_t size, uint32_t flags) vma_create(j6_handle_t *self, size_t size, uint32_t flags)
{ {
vm_flags f = vm_flags::user_mask & flags; vm_flags f = vm_flags::user_mask & flags;
construct_handle<vm_area_open>(handle, size, f); construct_handle<vm_area_open>(self, size, f);
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
vma_create_map(j6_handle_t *handle, size_t size, uintptr_t base, uint32_t flags) vma_create_map(j6_handle_t *self, size_t size, uintptr_t base, uint32_t flags)
{ {
vm_flags f = vm_flags::user_mask & flags; vm_flags f = vm_flags::user_mask & flags;
vm_area *a = construct_handle<vm_area_open>(handle, size, f); vm_area *a = construct_handle<vm_area_open>(self, size, f);
process::current().space().add(base, a); process::current().space().add(base, a);
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
vma_map(j6_handle_t handle, j6_handle_t proc, uintptr_t base) vma_map(vm_area *self, process *proc, uintptr_t base)
{ {
vm_area *a = get_handle<vm_area>(handle); proc->space().add(base, self);
if (!a) return j6_err_invalid_arg;
process *p = get_handle<process>(proc);
if (!p) return j6_err_invalid_arg;
p->space().add(base, a);
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
vma_unmap(j6_handle_t handle, j6_handle_t proc) vma_unmap(vm_area *self, process *proc)
{ {
vm_area *a = get_handle<vm_area>(handle); proc->space().remove(self);
if (!a) return j6_err_invalid_arg;
process *p = get_handle<process>(proc);
if (!p) return j6_err_invalid_arg;
p->space().remove(a);
return j6_status_ok; return j6_status_ok;
} }
j6_status_t j6_status_t
vma_resize(j6_handle_t handle, size_t *size) vma_resize(vm_area *self, size_t *size)
{ {
vm_area *a = get_handle<vm_area>(handle); *size = self->resize(*size);
if (!a) return j6_err_invalid_arg;
*size = a->resize(*size);
return j6_status_ok; return j6_status_ok;
} }

View File

@@ -44,7 +44,7 @@ TSS::ist_stack(unsigned ist)
void void
TSS::create_ist_stacks(uint8_t ist_entries) TSS::create_ist_stacks(uint8_t ist_entries)
{ {
extern vm_area_guarded &g_kernel_stacks; extern obj::vm_area_guarded &g_kernel_stacks;
using mem::frame_size; using mem::frame_size;
using mem::kernel_stack_pages; using mem::kernel_stack_pages;
constexpr size_t stack_bytes = kernel_stack_pages * frame_size; constexpr size_t stack_bytes = kernel_stack_pages * frame_size;

View File

@@ -12,6 +12,8 @@
#include "sysconf.h" #include "sysconf.h"
#include "vm_space.h" #include "vm_space.h"
using obj::vm_flags;
// The initial memory for the array of areas for the kernel space // The initial memory for the array of areas for the kernel space
constexpr size_t num_kernel_areas = 8; constexpr size_t num_kernel_areas = 8;
static uint64_t kernel_areas[num_kernel_areas * 2]; static uint64_t kernel_areas[num_kernel_areas * 2];
@@ -49,7 +51,7 @@ vm_space::vm_space() :
m_pml4->entries[i] = kpml4->entries[i]; m_pml4->entries[i] = kpml4->entries[i];
// Every vm space has sysconf in it // Every vm space has sysconf in it
vm_area *sysc = new vm_area_fixed( obj::vm_area *sysc = new obj::vm_area_fixed(
g_sysconf_phys, g_sysconf_phys,
sizeof(system_config), sizeof(system_config),
vm_flags::none); vm_flags::none);
@@ -74,11 +76,11 @@ vm_space::~vm_space()
vm_space & vm_space &
vm_space::kernel_space() vm_space::kernel_space()
{ {
return process::kernel_process().space(); return obj::process::kernel_process().space();
} }
bool bool
vm_space::add(uintptr_t base, vm_area *area) vm_space::add(uintptr_t base, obj::vm_area *area)
{ {
//TODO: check for collisions //TODO: check for collisions
m_areas.sorted_insert({base, area}); m_areas.sorted_insert({base, area});
@@ -88,7 +90,7 @@ vm_space::add(uintptr_t base, vm_area *area)
} }
void void
vm_space::remove_area(vm_area *area) vm_space::remove_area(obj::vm_area *area)
{ {
area->remove_from(this); area->remove_from(this);
clear(*area, 0, mem::page_count(area->size())); clear(*area, 0, mem::page_count(area->size()));
@@ -96,7 +98,7 @@ vm_space::remove_area(vm_area *area)
} }
bool bool
vm_space::remove(vm_area *area) vm_space::remove(obj::vm_area *area)
{ {
for (auto &a : m_areas) { for (auto &a : m_areas) {
if (a.area == area) { if (a.area == area) {
@@ -109,7 +111,7 @@ vm_space::remove(vm_area *area)
} }
bool bool
vm_space::can_resize(const vm_area &vma, size_t size) const vm_space::can_resize(const obj::vm_area &vma, size_t size) const
{ {
uintptr_t base = 0; uintptr_t base = 0;
unsigned n = m_areas.count(); unsigned n = m_areas.count();
@@ -131,7 +133,7 @@ vm_space::can_resize(const vm_area &vma, size_t size) const
return end <= space_end; return end <= space_end;
} }
vm_area * obj::vm_area *
vm_space::get(uintptr_t addr, uintptr_t *base) vm_space::get(uintptr_t addr, uintptr_t *base)
{ {
for (auto &a : m_areas) { for (auto &a : m_areas) {
@@ -145,7 +147,7 @@ vm_space::get(uintptr_t addr, uintptr_t *base)
} }
bool bool
vm_space::find_vma(const vm_area &vma, uintptr_t &base) const vm_space::find_vma(const obj::vm_area &vma, uintptr_t &base) const
{ {
for (auto &a : m_areas) { for (auto &a : m_areas) {
if (a.area != &vma) continue; if (a.area != &vma) continue;
@@ -156,7 +158,7 @@ vm_space::find_vma(const vm_area &vma, uintptr_t &base) const
} }
void void
vm_space::copy_from(const vm_space &source, const vm_area &vma) vm_space::copy_from(const vm_space &source, const obj::vm_area &vma)
{ {
uintptr_t to = 0; uintptr_t to = 0;
uintptr_t from = 0; uintptr_t from = 0;
@@ -177,7 +179,7 @@ vm_space::copy_from(const vm_space &source, const vm_area &vma)
} }
void void
vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t count) vm_space::page_in(const obj::vm_area &vma, uintptr_t offset, uintptr_t phys, size_t count)
{ {
using mem::frame_size; using mem::frame_size;
util::scoped_lock lock {m_lock}; util::scoped_lock lock {m_lock};
@@ -205,7 +207,7 @@ vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t c
} }
void void
vm_space::clear(const vm_area &vma, uintptr_t offset, size_t count, bool free) vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool free)
{ {
using mem::frame_size; using mem::frame_size;
util::scoped_lock lock {m_lock}; util::scoped_lock lock {m_lock};
@@ -245,7 +247,7 @@ vm_space::clear(const vm_area &vma, uintptr_t offset, size_t count, bool free)
} }
uintptr_t uintptr_t
vm_space::lookup(const vm_area &vma, uintptr_t offset) vm_space::lookup(const obj::vm_area &vma, uintptr_t offset)
{ {
uintptr_t base = 0; uintptr_t base = 0;
if (!find_vma(vma, base)) if (!find_vma(vma, base))
@@ -285,7 +287,7 @@ vm_space::handle_fault(uintptr_t addr, fault_type fault)
return false; return false;
uintptr_t base = 0; uintptr_t base = 0;
vm_area *area = get(addr, &base); obj::vm_area *area = get(addr, &base);
if (!area) if (!area)
return false; return false;

View File

@@ -10,9 +10,12 @@
#include "page_table.h" #include "page_table.h"
class process;
struct TCB; struct TCB;
class vm_area;
namespace obj {
class process;
class vm_area;
}
/// Tracks a region of virtual memory address space /// Tracks a region of virtual memory address space
class vm_space class vm_space
@@ -31,18 +34,18 @@ public:
/// \arg base The starting address of the area /// \arg base The starting address of the area
/// \arg area The area to add /// \arg area The area to add
/// \returns True if the add succeeded /// \returns True if the add succeeded
bool add(uintptr_t base, vm_area *area); bool add(uintptr_t base, obj::vm_area *area);
/// Remove a virtual memory area from this address space /// Remove a virtual memory area from this address space
/// \arg area The area to remove /// \arg area The area to remove
/// \returns True if the area was removed /// \returns True if the area was removed
bool remove(vm_area *area); bool remove(obj::vm_area *area);
/// Get the virtual memory area corresponding to an address /// Get the virtual memory area corresponding to an address
/// \arg addr The address to check /// \arg addr The address to check
/// \arg base [out] if not null, receives the base address of the area /// \arg base [out] if not null, receives the base address of the area
/// \returns The vm_area, or nullptr if not found /// \returns The vm_area, or nullptr if not found
vm_area * get(uintptr_t addr, uintptr_t *base = nullptr); obj::vm_area * get(uintptr_t addr, uintptr_t *base = nullptr);
/// Check if this is the kernel space /// Check if this is the kernel space
inline bool is_kernel() const { return m_kernel; } inline bool is_kernel() const { return m_kernel; }
@@ -55,17 +58,17 @@ public:
/// \arg offset Offset of the starting virutal address from the VMA base /// \arg offset Offset of the starting virutal address from the VMA base
/// \arg phys The starting physical address /// \arg phys The starting physical address
/// \arg count The number of contiugous physical pages to map /// \arg count The number of contiugous physical pages to map
void page_in(const vm_area &area, uintptr_t offset, uintptr_t phys, size_t count); void page_in(const obj::vm_area &area, uintptr_t offset, uintptr_t phys, size_t count);
/// Clear mappings from the given region /// Clear mappings from the given region
/// \arg area The VMA these mappings applies to /// \arg area The VMA these mappings applies to
/// \arg offset Offset of the starting virutal address from the VMA base /// \arg offset Offset of the starting virutal address from the VMA base
/// \arg count The number of pages worth of mappings to clear /// \arg count The number of pages worth of mappings to clear
/// \arg free If true, free the pages back to the system /// \arg free If true, free the pages back to the system
void clear(const vm_area &vma, uintptr_t start, size_t count, bool free = false); void clear(const obj::vm_area &vma, uintptr_t start, size_t count, bool free = false);
/// Look up the address of a given VMA's offset /// Look up the address of a given VMA's offset
uintptr_t lookup(const vm_area &vma, uintptr_t offset); uintptr_t lookup(const obj::vm_area &vma, uintptr_t offset);
/// Check if this space is the current active space /// Check if this space is the current active space
bool active() const; bool active() const;
@@ -108,26 +111,26 @@ public:
static size_t copy(vm_space &source, vm_space &dest, const void *from, void *to, size_t length); static size_t copy(vm_space &source, vm_space &dest, const void *from, void *to, size_t length);
private: private:
friend class vm_area; friend class obj::vm_area;
/// Find a given VMA in this address space /// Find a given VMA in this address space
bool find_vma(const vm_area &vma, uintptr_t &base) const; bool find_vma(const obj::vm_area &vma, uintptr_t &base) const;
/// Check if a VMA can be resized /// Check if a VMA can be resized
bool can_resize(const vm_area &vma, size_t size) const; bool can_resize(const obj::vm_area &vma, size_t size) const;
/// Copy a range of mappings from the given address space /// Copy a range of mappings from the given address space
void copy_from(const vm_space &source, const vm_area &vma); void copy_from(const vm_space &source, const obj::vm_area &vma);
/// Remove an area's mappings from this space /// Remove an area's mappings from this space
void remove_area(vm_area *area); void remove_area(obj::vm_area *area);
bool m_kernel; bool m_kernel;
page_table *m_pml4; page_table *m_pml4;
struct area { struct area {
uintptr_t base; uintptr_t base;
vm_area *area; obj::vm_area *area;
int compare(const struct area &o) const; int compare(const struct area &o) const;
bool operator==(const struct area &o) const; bool operator==(const struct area &o) const;
}; };

View File

@@ -27,14 +27,13 @@ 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. The least /// Handles are references and capabilities to other objects.
/// significant 32 bits are an identifier, and the most significant 32 typedef uint32_t j6_handle_t;
/// bits are a bitmask of capabilities this handle has on that object.
typedef uint64_t j6_handle_t;
#define j6_handle_rights_shift 4 #define j6_handle_invalid ((j6_handle_t)-1)
#define j6_handle_id_mask 0xffffffffull
#define j6_handle_invalid 0xffffffffull /// Bitfield for storage of capabilities
typedef uint32_t j6_cap_t;
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,