[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:
@@ -73,10 +73,10 @@ cpu_init(cpu_data *cpu, bool bsp)
|
||||
}
|
||||
|
||||
// Set the initial process as the kernel "process"
|
||||
extern process &g_kernel_process;
|
||||
extern obj::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,
|
||||
scheduler::max_priority,
|
||||
cpu->rsp0);
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
class GDT;
|
||||
class IDT;
|
||||
class lapic;
|
||||
class process;
|
||||
struct TCB;
|
||||
class thread;
|
||||
class TSS;
|
||||
|
||||
namespace obj {
|
||||
class process;
|
||||
class thread;
|
||||
}
|
||||
|
||||
struct cpu_state
|
||||
{
|
||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||
@@ -47,8 +50,8 @@ struct cpu_data
|
||||
uintptr_t rsp3;
|
||||
uint64_t rflags3;
|
||||
TCB *tcb;
|
||||
thread *thread;
|
||||
process *process;
|
||||
obj::thread *thread;
|
||||
obj::process *process;
|
||||
IDT *idt;
|
||||
TSS *tss;
|
||||
GDT *gdt;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#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 ";
|
||||
|
||||
@@ -380,7 +380,7 @@ device_manager::dispatch_irq(unsigned irq)
|
||||
if (irq >= m_irqs.count())
|
||||
return false;
|
||||
|
||||
endpoint *e = m_irqs[irq];
|
||||
obj::endpoint *e = m_irqs[irq];
|
||||
if (!e || e == ignore_endpoint)
|
||||
return e == ignore_endpoint;
|
||||
|
||||
@@ -389,7 +389,7 @@ device_manager::dispatch_irq(unsigned irq)
|
||||
}
|
||||
|
||||
bool
|
||||
device_manager::bind_irq(unsigned irq, endpoint *target)
|
||||
device_manager::bind_irq(unsigned irq, obj::endpoint *target)
|
||||
{
|
||||
// TODO: grow if under max size
|
||||
if (irq >= m_irqs.count())
|
||||
@@ -400,7 +400,7 @@ device_manager::bind_irq(unsigned irq, endpoint *target)
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::unbind_irqs(endpoint *target)
|
||||
device_manager::unbind_irqs(obj::endpoint *target)
|
||||
{
|
||||
const size_t count = m_irqs.count();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
|
||||
struct acpi_table_header;
|
||||
class block_device;
|
||||
class endpoint;
|
||||
|
||||
namespace obj {
|
||||
class endpoint;
|
||||
}
|
||||
|
||||
using irq_callback = void (*)(void *);
|
||||
|
||||
@@ -43,11 +46,11 @@ public:
|
||||
/// \arg irq The IRQ number to bind
|
||||
/// \arg target The endpoint to recieve messages when the IRQ is signalled
|
||||
/// \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
|
||||
/// \arg target The endpoint to remove
|
||||
void unbind_irqs(endpoint *target);
|
||||
void unbind_irqs(obj::endpoint *target);
|
||||
|
||||
/// Allocate an MSI IRQ for a device
|
||||
/// \arg name Name of the interrupt, for display to user
|
||||
@@ -161,7 +164,7 @@ private:
|
||||
util::vector<pci_group> m_pci;
|
||||
util::vector<pci_device> m_devices;
|
||||
|
||||
util::vector<endpoint*> m_irqs;
|
||||
util::vector<obj::endpoint*> m_irqs;
|
||||
|
||||
util::vector<block_device *> m_blockdevs;
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ isr_handler(cpu_state *regs)
|
||||
static_cast<vm_space::fault_type>(regs->errorcode);
|
||||
|
||||
vm_space &space = user
|
||||
? process::current().space()
|
||||
? obj::process::current().space()
|
||||
: vm_space::kernel_space();
|
||||
|
||||
if (cr2 && space.handle_fault(cr2, ft))
|
||||
|
||||
@@ -86,7 +86,7 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
||||
memcpy(out, buffer, n);
|
||||
m_buffer.commit(n);
|
||||
|
||||
system &sys = system::get();
|
||||
obj::system &sys = obj::system::get();
|
||||
sys.assert_signal(j6_signal_system_has_log);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,10 +153,11 @@ start_aps(lapic &apic, const util::vector<uint8_t> &ids, void *kpml4)
|
||||
{
|
||||
using mem::frame_size;
|
||||
using mem::kernel_stack_pages;
|
||||
using obj::vm_flags;
|
||||
|
||||
extern size_t ap_startup_code_size;
|
||||
extern process &g_kernel_process;
|
||||
extern vm_area_guarded &g_kernel_stacks;
|
||||
extern obj::process &g_kernel_process;
|
||||
extern obj::vm_area_guarded &g_kernel_stacks;
|
||||
|
||||
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
|
||||
uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses
|
||||
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);
|
||||
memcpy(
|
||||
reinterpret_cast<void*>(addr),
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
using bootproto::allocation_register;
|
||||
using bootproto::section_flags;
|
||||
|
||||
using obj::vm_flags;
|
||||
|
||||
extern "C" void initialize_main_thread();
|
||||
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;
|
||||
frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value;
|
||||
|
||||
static util::no_construct<vm_area_untracked> __g_kernel_heap_area_storage;
|
||||
vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value;
|
||||
static util::no_construct<obj::vm_area_untracked> __g_kernel_heap_area_storage;
|
||||
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;
|
||||
vm_area_guarded &g_kernel_stacks = __g_kernel_stacks_storage.value;
|
||||
static util::no_construct<obj::vm_area_guarded> __g_kernel_stacks_storage;
|
||||
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::kernel_buffer_pages,
|
||||
mem::buffers_size,
|
||||
@@ -81,15 +83,15 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
||||
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_area *heap = new (&g_kernel_heap_area)
|
||||
vm_area_untracked(mem::heap_size, vm_flags::write);
|
||||
obj::vm_area *heap = new (&g_kernel_heap_area)
|
||||
obj::vm_area_untracked(mem::heap_size, vm_flags::write);
|
||||
|
||||
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::kernel_stack_pages,
|
||||
mem::stacks_size,
|
||||
@@ -171,8 +173,8 @@ log_mtrrs()
|
||||
void
|
||||
load_init_server(bootproto::program &program, uintptr_t modules_address)
|
||||
{
|
||||
process *p = new process;
|
||||
p->add_handle(&system::get());
|
||||
obj::process *p = new obj::process;
|
||||
p->add_handle(&obj::system::get(), obj::system::init_caps);
|
||||
|
||||
vm_space &space = p->space();
|
||||
for (const auto § : 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::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);
|
||||
}
|
||||
|
||||
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->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
|
||||
// its own stack. We take advantage of that to use rsp to pass it the init modules
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include "objects/channel.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;
|
||||
|
||||
@@ -89,3 +91,5 @@ channel::on_no_handles()
|
||||
kobject::on_no_handles();
|
||||
delete this;
|
||||
}
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -7,11 +7,16 @@
|
||||
|
||||
#include "objects/kobject.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
/// Channels are bi-directional means of sending messages
|
||||
class channel :
|
||||
public kobject
|
||||
{
|
||||
public:
|
||||
/// Capabilities on a newly constructed channel handle
|
||||
constexpr static j6_cap_t creation_caps = 0;
|
||||
|
||||
channel();
|
||||
virtual ~channel();
|
||||
|
||||
@@ -48,3 +53,5 @@ private:
|
||||
uintptr_t m_data;
|
||||
util::bip_buffer m_buffer;
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "objects/thread.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
endpoint::endpoint() :
|
||||
kobject {kobject::type::endpoint}
|
||||
{}
|
||||
@@ -135,3 +137,5 @@ endpoint::do_message_copy(const endpoint::thread_data &sender, endpoint::thread_
|
||||
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -7,11 +7,16 @@
|
||||
|
||||
#include "objects/kobject.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
/// Endpoints are objects that enable synchronous message-passing IPC
|
||||
class endpoint :
|
||||
public kobject
|
||||
{
|
||||
public:
|
||||
/// Capabilities on a newly constructed endpoint handle
|
||||
constexpr static j6_cap_t creation_caps = 0;
|
||||
|
||||
endpoint();
|
||||
virtual ~endpoint();
|
||||
|
||||
@@ -69,3 +74,5 @@ private:
|
||||
|
||||
util::vector<thread_data> m_blocked;
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
|
||||
#include "objects/kobject.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
class event :
|
||||
public kobject
|
||||
{
|
||||
public:
|
||||
/// Capabilities on a newly constructed event handle
|
||||
constexpr static j6_cap_t creation_caps = 0;
|
||||
|
||||
event() :
|
||||
kobject(type::event) {}
|
||||
|
||||
static constexpr kobject::type type = kobject::type::event;
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
82
src/kernel/objects/handle.h
Normal file
82
src/kernel/objects/handle.h
Normal 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
|
||||
@@ -6,7 +6,8 @@
|
||||
#include "objects/kobject.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 };
|
||||
|
||||
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");
|
||||
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
|
||||
@@ -74,3 +76,5 @@ kobject::on_no_handles()
|
||||
{
|
||||
assert_signal(j6_signal_no_handles);
|
||||
}
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <j6/types.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
namespace obj {
|
||||
|
||||
class thread;
|
||||
|
||||
/// Base type for all user-interactable kernel objects
|
||||
@@ -98,3 +100,5 @@ private:
|
||||
protected:
|
||||
util::vector<thread*> m_blocked_threads;
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -7,19 +7,22 @@
|
||||
#include "objects/vm_area.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
|
||||
// This object is initialized _before_ global constructors are called,
|
||||
// so we don't want it to have a global constructor at all, lest it
|
||||
// overwrite the previous initialization.
|
||||
static util::no_construct<process> __g_kernel_process_storage;
|
||||
process &g_kernel_process = __g_kernel_process_storage.value;
|
||||
static util::no_construct<obj::process> __g_kernel_process_storage;
|
||||
obj::process &g_kernel_process = __g_kernel_process_storage.value;
|
||||
|
||||
|
||||
namespace obj {
|
||||
|
||||
process::process() :
|
||||
kobject {kobject::type::process},
|
||||
m_next_handle {1},
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -34,8 +37,6 @@ process::process(page_table *kpml4) :
|
||||
|
||||
process::~process()
|
||||
{
|
||||
for (auto &it : m_handles)
|
||||
if (it.val) it.val->handle_release();
|
||||
}
|
||||
|
||||
process & process::current() { return *current_cpu().process; }
|
||||
@@ -123,27 +124,27 @@ process::thread_exited(thread *th)
|
||||
}
|
||||
|
||||
j6_handle_t
|
||||
process::add_handle(kobject *obj)
|
||||
process::add_handle(kobject *obj, j6_cap_t caps)
|
||||
{
|
||||
if (!obj)
|
||||
return j6_handle_invalid;
|
||||
|
||||
obj->handle_retain();
|
||||
j6_handle_t handle = m_next_handle++;
|
||||
m_handles.insert(handle, obj);
|
||||
return handle;
|
||||
j6_handle_t id = m_next_handle++;
|
||||
m_handles.insert(id, {id, obj, caps});
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
bool
|
||||
process::remove_handle(j6_handle_t handle)
|
||||
process::remove_handle(j6_handle_t id)
|
||||
{
|
||||
kobject *obj = m_handles.find(handle);
|
||||
if (obj) obj->handle_release();
|
||||
return m_handles.erase(handle);
|
||||
return m_handles.erase(id);
|
||||
}
|
||||
|
||||
kobject *
|
||||
process::lookup_handle(j6_handle_t handle)
|
||||
handle *
|
||||
process::lookup_handle(j6_handle_t id)
|
||||
{
|
||||
return m_handles.find(handle);
|
||||
return m_handles.find(id);
|
||||
}
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -5,14 +5,23 @@
|
||||
#include <util/map.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
#include "objects/handle.h"
|
||||
#include "objects/kobject.h"
|
||||
#include "page_table.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
class process :
|
||||
public kobject
|
||||
{
|
||||
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
|
||||
constexpr static uintptr_t stacks_top = 0x0000800000000000;
|
||||
|
||||
@@ -51,8 +60,9 @@ public:
|
||||
|
||||
/// Start tracking an object with a handle.
|
||||
/// \args obj The object this handle refers to
|
||||
/// \args caps The capabilities on this handle
|
||||
/// \returns The new handle 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.
|
||||
/// \args handle The handle that refers to the object
|
||||
@@ -61,8 +71,8 @@ public:
|
||||
|
||||
/// Lookup an object for a handle
|
||||
/// \args handle The handle to the object
|
||||
/// \returns Pointer to the object, or null if not found
|
||||
kobject * lookup_handle(j6_handle_t handle);
|
||||
/// \returns Pointer to the handle struct, or null if not found
|
||||
handle * lookup_handle(j6_handle_t handle);
|
||||
|
||||
/// Inform the process of an exited thread
|
||||
/// \args th The thread which has exited
|
||||
@@ -90,9 +100,12 @@ private:
|
||||
vm_space m_space;
|
||||
|
||||
util::vector<thread*> m_threads;
|
||||
util::map<j6_handle_t, kobject*> m_handles;
|
||||
|
||||
j6_handle_t m_next_handle;
|
||||
util::map<j6_handle_t, handle> m_handles;
|
||||
|
||||
enum class state : uint8_t { running, exited };
|
||||
state m_state;
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "objects/system.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
system system::s_instance;
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -4,11 +4,16 @@
|
||||
|
||||
#include "objects/kobject.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
class system :
|
||||
public kobject
|
||||
{
|
||||
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; }
|
||||
|
||||
@@ -16,3 +21,5 @@ private:
|
||||
static system s_instance;
|
||||
system() : kobject(type::system) {}
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
#include "scheduler.h"
|
||||
|
||||
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) :
|
||||
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_creator = current_cpu().thread;
|
||||
m_self_handle = parent.add_handle(this);
|
||||
m_self_handle = parent.add_handle(this, thread::parent_caps);
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
@@ -246,3 +249,5 @@ thread::create_idle_thread(process &kernel, uint8_t pri, uintptr_t rsp0)
|
||||
idle->set_state(state::ready);
|
||||
return idle;
|
||||
}
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
#include "objects/kobject.h"
|
||||
|
||||
struct page_table;
|
||||
class process;
|
||||
|
||||
namespace obj {
|
||||
class thread;
|
||||
}
|
||||
|
||||
struct TCB
|
||||
{
|
||||
@@ -22,7 +25,7 @@ struct TCB
|
||||
uintptr_t pml4;
|
||||
// End of area used by asembly
|
||||
|
||||
thread* thread;
|
||||
obj::thread* thread;
|
||||
|
||||
uint8_t priority;
|
||||
// note: 3 bytes padding
|
||||
@@ -38,6 +41,9 @@ struct TCB
|
||||
using tcb_list = util::linked_list<TCB>;
|
||||
using tcb_node = tcb_list::item_type;
|
||||
|
||||
|
||||
namespace obj {
|
||||
|
||||
enum class wait_type : uint8_t
|
||||
{
|
||||
none = 0x00,
|
||||
@@ -47,10 +53,17 @@ enum class wait_type : uint8_t
|
||||
};
|
||||
is_bitfield(wait_type);
|
||||
|
||||
class process;
|
||||
|
||||
class thread :
|
||||
public kobject
|
||||
{
|
||||
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 {
|
||||
ready = 0x01,
|
||||
@@ -203,3 +216,5 @@ private:
|
||||
|
||||
j6_handle_t m_self_handle;
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "page_tree.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
namespace obj {
|
||||
|
||||
using mem::frame_size;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
class page_tree;
|
||||
class vm_space;
|
||||
|
||||
|
||||
namespace obj {
|
||||
|
||||
enum class vm_flags : uint32_t
|
||||
{
|
||||
#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
|
||||
user_mask = 0x0000ffff, ///< flags allowed via syscall for non-drivers
|
||||
};
|
||||
is_bitfield(vm_flags);
|
||||
|
||||
|
||||
/// Virtual memory areas allow control over memory allocation
|
||||
@@ -29,6 +33,9 @@ class vm_area :
|
||||
public kobject
|
||||
{
|
||||
public:
|
||||
/// Capabilities on a newly constructed vma handle
|
||||
constexpr static j6_cap_t creation_caps = 0;
|
||||
|
||||
static constexpr kobject::type type = kobject::type::vma;
|
||||
|
||||
/// Constructor.
|
||||
@@ -170,5 +177,4 @@ private:
|
||||
uintptr_t m_next;
|
||||
};
|
||||
|
||||
|
||||
is_bitfield(vm_flags);
|
||||
} // namespace obj
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "objects/vm_area.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
using obj::process;
|
||||
using obj::thread;
|
||||
|
||||
extern "C" void task_switch(TCB *tcb);
|
||||
scheduler *scheduler::s_instance = nullptr;
|
||||
|
||||
@@ -12,10 +12,13 @@ namespace args {
|
||||
|
||||
struct cpu_data;
|
||||
class lapic;
|
||||
class process;
|
||||
struct page_table;
|
||||
struct run_queue;
|
||||
|
||||
namespace obj {
|
||||
class process;
|
||||
class thread;
|
||||
}
|
||||
|
||||
/// The task scheduler
|
||||
class scheduler
|
||||
@@ -47,7 +50,7 @@ public:
|
||||
/// Create a new process from a program image in memory.
|
||||
/// \arg program The descriptor of the pogram in memory
|
||||
/// \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
|
||||
/// \arg proc Function to run as a kernel task
|
||||
@@ -77,7 +80,7 @@ public:
|
||||
static scheduler & get() { return *s_instance; }
|
||||
|
||||
private:
|
||||
friend class process;
|
||||
friend class obj::process;
|
||||
|
||||
static constexpr uint64_t promote_frequency = 10;
|
||||
static constexpr uint64_t steal_frequency = 10;
|
||||
@@ -89,7 +92,7 @@ private:
|
||||
uint32_t m_next_pid;
|
||||
uint32_t m_tick_count;
|
||||
|
||||
process *m_kernel_process;
|
||||
obj::process *m_kernel_process;
|
||||
|
||||
util::vector<run_queue> m_run_queues;
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ namespace syscalls
|
||||
|
||||
args = []
|
||||
if method.constructor:
|
||||
args.append("j6_handle_t *handle")
|
||||
args.append("j6_handle_t *self")
|
||||
elif not method.static:
|
||||
args.append("j6_handle_t handle")
|
||||
args.append("j6_handle_t self")
|
||||
|
||||
for param in method.params:
|
||||
for type, suffix in param.type.c_names(param.options):
|
||||
|
||||
@@ -4,6 +4,21 @@
|
||||
#include <arch/memory.h>
|
||||
#include <j6/errors.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 {
|
||||
template <typename T>
|
||||
@@ -16,13 +31,9 @@ namespace {
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
using util::buffer;
|
||||
|
||||
/*[[[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"}
|
||||
|
||||
for id, scope, method in syscalls.methods:
|
||||
@@ -33,21 +44,40 @@ for id, scope, method in syscalls.methods:
|
||||
|
||||
args = []
|
||||
argdefs = []
|
||||
cxxargdefs = []
|
||||
refparams = []
|
||||
handles = []
|
||||
|
||||
if method.constructor:
|
||||
argdefs.append("j6_handle_t *handle")
|
||||
args.append("handle")
|
||||
refparams.append(("handle", False))
|
||||
argdefs.append("j6_handle_t *self")
|
||||
cxxargdefs.append("j6_handle_t *self")
|
||||
args.append("self")
|
||||
refparams.append(("self", False))
|
||||
|
||||
elif not method.static:
|
||||
argdefs.append("j6_handle_t handle")
|
||||
args.append("handle")
|
||||
argdefs.append("j6_handle_t self")
|
||||
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:
|
||||
needs_obj = param.type.needs_object(param.options)
|
||||
|
||||
for type, suffix in param.type.c_names(param.options):
|
||||
arg = f"{param.name}{suffix}"
|
||||
argdefs.append(f"{type} {arg}")
|
||||
args.append(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)
|
||||
|
||||
|
||||
if param.refparam:
|
||||
subs = param.type.c_names(param.options)
|
||||
@@ -56,7 +86,7 @@ for id, scope, method in syscalls.methods:
|
||||
for sub in subs[1:]:
|
||||
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)}) {{""")
|
||||
|
||||
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()
|
||||
|
||||
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("\n")
|
||||
]]]*/
|
||||
|
||||
@@ -4,29 +4,27 @@
|
||||
#include "objects/channel.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!c) return j6_err_invalid_arg;
|
||||
return c->enqueue(len, data);
|
||||
return self->enqueue(len, data);
|
||||
}
|
||||
|
||||
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);
|
||||
if (!c) return j6_err_invalid_arg;
|
||||
return c->dequeue(len, data);
|
||||
return self->dequeue(len, data);
|
||||
}
|
||||
|
||||
} // namespace syscalls
|
||||
|
||||
@@ -5,62 +5,61 @@
|
||||
#include "objects/endpoint.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
endpoint *e = get_handle<endpoint>(handle);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
return e->send(tag, data, data_len);
|
||||
return self->send(tag, data, data_len);
|
||||
}
|
||||
|
||||
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 not optional.
|
||||
if (!data_len || (*data_len && !data))
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
endpoint *e = get_handle<endpoint>(handle);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
// 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;
|
||||
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;
|
||||
*data_len = out_len;
|
||||
return s;
|
||||
}
|
||||
|
||||
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)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
endpoint *e = get_handle<endpoint>(handle);
|
||||
if (!e) return j6_err_invalid_arg;
|
||||
|
||||
j6_status_t status = e->send(*tag, data, *data_len);
|
||||
j6_status_t status = self->send(*tag, data, *data_len);
|
||||
if (status != j6_status_ok)
|
||||
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;
|
||||
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;
|
||||
*data_len = out_len;
|
||||
return s;
|
||||
|
||||
@@ -10,38 +10,41 @@
|
||||
namespace syscalls {
|
||||
|
||||
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...};
|
||||
*handle = p.add_handle(o);
|
||||
*id = p.add_handle(o, T::creation_caps);
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T * get_handle(j6_handle_t handle)
|
||||
obj::handle * get_handle(j6_handle_t id)
|
||||
{
|
||||
process &p = process::current();
|
||||
kobject *o = p.lookup_handle(handle);
|
||||
if (!o || o->get_type() != T::type)
|
||||
obj::process &p = obj::process::current();
|
||||
obj::handle *h = p.lookup_handle(id);
|
||||
if (!h || h->type() != T::type)
|
||||
return nullptr;
|
||||
return static_cast<T*>(o);
|
||||
return h;
|
||||
}
|
||||
|
||||
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();
|
||||
return p.lookup_handle(handle);
|
||||
obj::process &p = obj::process::current();
|
||||
return p.lookup_handle(id);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T * remove_handle(j6_handle_t handle)
|
||||
T * remove_handle(j6_handle_t id)
|
||||
{
|
||||
T *o = get_handle<T>(handle);
|
||||
if (o) {
|
||||
process &p = process::current();
|
||||
p.remove_handle(handle);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,34 +8,28 @@
|
||||
#include "objects/thread.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
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);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
*koid = obj->koid();
|
||||
*koid = self->koid();
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
j6_signal_t current = obj->signals();
|
||||
j6_signal_t current = self->signals();
|
||||
if ((current & mask) != 0) {
|
||||
*sigs = current;
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
thread &th = thread::current();
|
||||
obj->add_blocked_thread(&th);
|
||||
self->add_blocked_thread(&th);
|
||||
th.wait_on_signals(mask);
|
||||
|
||||
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
|
||||
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)};
|
||||
|
||||
for (unsigned i = 0; i < handles_count; ++i) {
|
||||
j6_handle_t h = handles[i];
|
||||
if (h == j6_handle_invalid)
|
||||
j6_handle_t hid = handles[i];
|
||||
if (hid == j6_handle_invalid)
|
||||
continue;
|
||||
|
||||
kobject *obj = get_handle<kobject>(h);
|
||||
if (!obj)
|
||||
handle *h = get_handle<kobject>(hid);
|
||||
if (!h || !h->object)
|
||||
return j6_err_invalid_arg;
|
||||
kobject *obj = h->object;
|
||||
|
||||
j6_signal_t current = obj->signals();
|
||||
if ((current & mask) != 0) {
|
||||
*signals = current;
|
||||
*handle = h;
|
||||
*woken = hid;
|
||||
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)
|
||||
return result;
|
||||
|
||||
*handle = j6_handle_invalid;
|
||||
*woken = j6_handle_invalid;
|
||||
*signals = th.get_wait_data();
|
||||
j6_koid_t koid = th.get_wait_object();
|
||||
for (unsigned i = 0; i < handles_count; ++i) {
|
||||
if (koid == objects[i]->koid())
|
||||
*handle = handles[i];
|
||||
*woken = handles[i];
|
||||
else
|
||||
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");
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
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)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
kobject *obj = get_handle<kobject>(handle);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
obj->assert_signal(signals);
|
||||
self->assert_signal(signals);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
kobject_close(j6_handle_t handle)
|
||||
kobject_close(kobject *self)
|
||||
{
|
||||
kobject *obj = get_handle<kobject>(handle);
|
||||
if (!obj)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
obj->close();
|
||||
self->close();
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,41 +5,25 @@
|
||||
#include "objects/process.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
process_create(j6_handle_t *handle)
|
||||
process_create(j6_handle_t *self)
|
||||
{
|
||||
process *child = construct_handle<process>(handle);
|
||||
log::debug(logs::task, "Process %llx created", child->koid());
|
||||
process *p = construct_handle<process>(self);
|
||||
log::debug(logs::task, "Process %llx created", p->koid());
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
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 *c = get_handle<process>(handle);
|
||||
if (handles_count && !handles)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
for (size_t i = 0; i < handles_count; ++i) {
|
||||
kobject *o = p.lookup_handle(handles[i]);
|
||||
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);
|
||||
log::debug(logs::task, "Process %llx killed by process %llx", self->koid(), p.koid());
|
||||
self->exit(-1u);
|
||||
|
||||
return j6_status_ok;
|
||||
}
|
||||
@@ -57,16 +41,13 @@ process_exit(int32_t status)
|
||||
}
|
||||
|
||||
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);
|
||||
if (!dest) return j6_err_invalid_arg;
|
||||
handle *target_handle = get_handle<kobject>(target);
|
||||
j6_handle_t out = self->add_handle(target_handle->object, target_handle->caps);
|
||||
|
||||
kobject *o = get_handle<kobject>(sender);
|
||||
j6_handle_t out = dest->add_handle(o);
|
||||
|
||||
if (receiver)
|
||||
*receiver = out;
|
||||
if (received)
|
||||
*received = out;
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
|
||||
extern log::logger &g_logger;
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
using system = class ::system;
|
||||
|
||||
j6_status_t
|
||||
log(const char *message)
|
||||
{
|
||||
@@ -33,7 +37,7 @@ noop()
|
||||
}
|
||||
|
||||
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 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;
|
||||
*buffer_len = g_logger.get_entry(buffer, *buffer_len);
|
||||
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;
|
||||
}
|
||||
|
||||
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 (!e) return j6_err_invalid_arg;
|
||||
|
||||
if (device_manager::get().bind_irq(irq, e))
|
||||
if (device_manager::get().bind_irq(irq, endp))
|
||||
return j6_status_ok;
|
||||
|
||||
return j6_err_invalid_arg;
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
system_request_iopl(j6_handle_t handle, unsigned iopl)
|
||||
system_request_iopl(system *self, unsigned iopl)
|
||||
{
|
||||
if (iopl != 0 && iopl != 3)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
@@ -6,25 +6,24 @@
|
||||
#include "objects/thread.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
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();
|
||||
process &parent_pr = parent_th.parent();
|
||||
|
||||
process *owner = get_handle<process>(proc);
|
||||
if (!owner) return j6_err_invalid_arg;
|
||||
|
||||
thread *child = owner->create_thread(stack_top);
|
||||
thread *child = proc->create_thread(stack_top);
|
||||
child->add_thunk_user(entrypoint);
|
||||
*handle = child->self_handle();
|
||||
*self = child->self_handle();
|
||||
child->clear_state(thread::state::loading);
|
||||
child->set_state(thread::state::ready);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -41,14 +40,10 @@ thread_exit(int32_t status)
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
thread_kill(j6_handle_t handle)
|
||||
thread_kill(thread *self)
|
||||
{
|
||||
thread *th = get_handle<thread>(handle);
|
||||
if (!th)
|
||||
return j6_err_invalid_arg;
|
||||
|
||||
log::debug(logs::task, "Killing thread %llx", th->koid());
|
||||
th->exit(-1);
|
||||
log::debug(logs::task, "Killing thread %llx", self->koid());
|
||||
self->exit(-1);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,58 +8,45 @@
|
||||
#include "syscalls/helpers.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
using namespace obj;
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
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;
|
||||
construct_handle<vm_area_open>(handle, size, f);
|
||||
construct_handle<vm_area_open>(self, size, f);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
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_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);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
proc->space().add(base, self);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!a) return j6_err_invalid_arg;
|
||||
|
||||
process *p = get_handle<process>(proc);
|
||||
if (!p) return j6_err_invalid_arg;
|
||||
|
||||
p->space().remove(a);
|
||||
proc->space().remove(self);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!a) return j6_err_invalid_arg;
|
||||
|
||||
*size = a->resize(*size);
|
||||
*size = self->resize(*size);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ TSS::ist_stack(unsigned ist)
|
||||
void
|
||||
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::kernel_stack_pages;
|
||||
constexpr size_t stack_bytes = kernel_stack_pages * frame_size;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "sysconf.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
using obj::vm_flags;
|
||||
|
||||
// The initial memory for the array of areas for the kernel space
|
||||
constexpr size_t num_kernel_areas = 8;
|
||||
static uint64_t kernel_areas[num_kernel_areas * 2];
|
||||
@@ -49,7 +51,7 @@ vm_space::vm_space() :
|
||||
m_pml4->entries[i] = kpml4->entries[i];
|
||||
|
||||
// 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,
|
||||
sizeof(system_config),
|
||||
vm_flags::none);
|
||||
@@ -74,11 +76,11 @@ vm_space::~vm_space()
|
||||
vm_space &
|
||||
vm_space::kernel_space()
|
||||
{
|
||||
return process::kernel_process().space();
|
||||
return obj::process::kernel_process().space();
|
||||
}
|
||||
|
||||
bool
|
||||
vm_space::add(uintptr_t base, vm_area *area)
|
||||
vm_space::add(uintptr_t base, obj::vm_area *area)
|
||||
{
|
||||
//TODO: check for collisions
|
||||
m_areas.sorted_insert({base, area});
|
||||
@@ -88,7 +90,7 @@ vm_space::add(uintptr_t base, vm_area *area)
|
||||
}
|
||||
|
||||
void
|
||||
vm_space::remove_area(vm_area *area)
|
||||
vm_space::remove_area(obj::vm_area *area)
|
||||
{
|
||||
area->remove_from(this);
|
||||
clear(*area, 0, mem::page_count(area->size()));
|
||||
@@ -96,7 +98,7 @@ vm_space::remove_area(vm_area *area)
|
||||
}
|
||||
|
||||
bool
|
||||
vm_space::remove(vm_area *area)
|
||||
vm_space::remove(obj::vm_area *area)
|
||||
{
|
||||
for (auto &a : m_areas) {
|
||||
if (a.area == area) {
|
||||
@@ -109,7 +111,7 @@ vm_space::remove(vm_area *area)
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
vm_area *
|
||||
obj::vm_area *
|
||||
vm_space::get(uintptr_t addr, uintptr_t *base)
|
||||
{
|
||||
for (auto &a : m_areas) {
|
||||
@@ -145,7 +147,7 @@ vm_space::get(uintptr_t addr, uintptr_t *base)
|
||||
}
|
||||
|
||||
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) {
|
||||
if (a.area != &vma) continue;
|
||||
@@ -156,7 +158,7 @@ vm_space::find_vma(const vm_area &vma, uintptr_t &base) const
|
||||
}
|
||||
|
||||
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 from = 0;
|
||||
@@ -177,7 +179,7 @@ vm_space::copy_from(const vm_space &source, const vm_area &vma)
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
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;
|
||||
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
|
||||
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;
|
||||
if (!find_vma(vma, base))
|
||||
@@ -285,7 +287,7 @@ vm_space::handle_fault(uintptr_t addr, fault_type fault)
|
||||
return false;
|
||||
|
||||
uintptr_t base = 0;
|
||||
vm_area *area = get(addr, &base);
|
||||
obj::vm_area *area = get(addr, &base);
|
||||
if (!area)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
|
||||
#include "page_table.h"
|
||||
|
||||
class process;
|
||||
struct TCB;
|
||||
class vm_area;
|
||||
|
||||
namespace obj {
|
||||
class process;
|
||||
class vm_area;
|
||||
}
|
||||
|
||||
/// Tracks a region of virtual memory address space
|
||||
class vm_space
|
||||
@@ -31,18 +34,18 @@ public:
|
||||
/// \arg base The starting address of the area
|
||||
/// \arg area The area to add
|
||||
/// \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
|
||||
/// \arg area The area to remove
|
||||
/// \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
|
||||
/// \arg addr The address to check
|
||||
/// \arg base [out] if not null, receives the base address of the area
|
||||
/// \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
|
||||
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 phys The starting physical address
|
||||
/// \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
|
||||
/// \arg area The VMA these mappings applies to
|
||||
/// \arg offset Offset of the starting virutal address from the VMA base
|
||||
/// \arg count The number of pages worth of mappings to clear
|
||||
/// \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
|
||||
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
|
||||
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);
|
||||
|
||||
private:
|
||||
friend class vm_area;
|
||||
friend class obj::vm_area;
|
||||
|
||||
/// 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
|
||||
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
|
||||
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
|
||||
void remove_area(vm_area *area);
|
||||
void remove_area(obj::vm_area *area);
|
||||
|
||||
bool m_kernel;
|
||||
page_table *m_pml4;
|
||||
|
||||
struct area {
|
||||
uintptr_t base;
|
||||
vm_area *area;
|
||||
obj::vm_area *area;
|
||||
int compare(const struct area &o) const;
|
||||
bool operator==(const struct area &o) const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user