mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
Add initial pass of syscall API kobjects
This commit is contained in:
@@ -34,6 +34,8 @@ modules:
|
|||||||
- src/kernel/main.cpp
|
- src/kernel/main.cpp
|
||||||
- src/kernel/memory_bootstrap.cpp
|
- src/kernel/memory_bootstrap.cpp
|
||||||
- src/kernel/msr.cpp
|
- src/kernel/msr.cpp
|
||||||
|
- src/kernel/objects/handle.cpp
|
||||||
|
- src/kernel/objects/kobject.cpp
|
||||||
- src/kernel/page_manager.cpp
|
- src/kernel/page_manager.cpp
|
||||||
- src/kernel/pci.cpp
|
- src/kernel/pci.cpp
|
||||||
- src/kernel/process.cpp
|
- src/kernel/process.cpp
|
||||||
|
|||||||
16
src/include/j6/errors.h
Normal file
16
src/include/j6/errors.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file errors.h
|
||||||
|
/// Collection of constants for the j6_status_t type
|
||||||
|
|
||||||
|
#define j6_status_error 0x8000000000000000
|
||||||
|
#define j6_err(x) ((x) | j6_status_error)
|
||||||
|
#define j6_is_err(x) (((x) & j6_status_error) == j6_status_error)
|
||||||
|
|
||||||
|
#define j6_status_ok 0x0000
|
||||||
|
|
||||||
|
#define j6_status_destroyed 0x1001
|
||||||
|
|
||||||
|
#define j6_err_nyi j6_err(0x0001)
|
||||||
|
#define j6_err_unexpected j6_err(0x0002)
|
||||||
|
#define j6_err_invalid_arg j6_err(0x0003)
|
||||||
|
|
||||||
18
src/include/j6/signals.h
Normal file
18
src/include/j6/signals.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file signals.h
|
||||||
|
/// Collection of constants for the j6_signal_t type
|
||||||
|
|
||||||
|
// Signals 0-7 are common to all types
|
||||||
|
#define j6_signal_no_handles (1 << 0)
|
||||||
|
|
||||||
|
// Signals 8-15 are user-defined signals
|
||||||
|
#define j6_signal_user0 (1 << 8)
|
||||||
|
#define j6_signal_user1 (1 << 9)
|
||||||
|
#define j6_signal_user2 (1 << 10)
|
||||||
|
#define j6_signal_user3 (1 << 11)
|
||||||
|
#define j6_signal_user4 (1 << 12)
|
||||||
|
#define j6_signal_user5 (1 << 13)
|
||||||
|
#define j6_signal_user6 (1 << 14)
|
||||||
|
#define j6_signal_user7 (1 << 15)
|
||||||
|
|
||||||
|
// All other signals are type-specific
|
||||||
20
src/include/j6/types.h
Normal file
20
src/include/j6/types.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file types.h
|
||||||
|
/// Basic kernel types exposed to userspace
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/// All interactable kernel objects have a uniqe kernel object id
|
||||||
|
typedef uint64_t j6_koid_t;
|
||||||
|
|
||||||
|
/// Syscalls return status as this type
|
||||||
|
typedef uint32_t j6_status_t;
|
||||||
|
|
||||||
|
/// Handles are references and capabilities to other objects
|
||||||
|
typedef uint32_t j6_handle_t;
|
||||||
|
|
||||||
|
/// Some objects have signals, which are a bitmap of 64 possible signals
|
||||||
|
typedef uint64_t j6_signal_t;
|
||||||
|
|
||||||
|
/// The rights of a handle/capability are a bitmap of 64 possible rights
|
||||||
|
typedef uint64_t j6_rights_t;
|
||||||
@@ -8,3 +8,4 @@ LOG(task, info);
|
|||||||
LOG(boot, debug);
|
LOG(boot, debug);
|
||||||
LOG(syscall,debug);
|
LOG(syscall,debug);
|
||||||
LOG(vmem, debug);
|
LOG(vmem, debug);
|
||||||
|
LOG(objs, debug);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "j6/signals.h"
|
||||||
|
|
||||||
#include "initrd/initrd.h"
|
#include "initrd/initrd.h"
|
||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
#include "kutil/heap_allocator.h"
|
#include "kutil/heap_allocator.h"
|
||||||
@@ -16,6 +18,8 @@
|
|||||||
#include "kernel_args.h"
|
#include "kernel_args.h"
|
||||||
#include "kernel_memory.h"
|
#include "kernel_memory.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "objects/event.h"
|
||||||
|
#include "objects/handle.h"
|
||||||
#include "page_manager.h"
|
#include "page_manager.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
@@ -30,6 +34,26 @@ extern void __kernel_assert(const char *, unsigned, const char *);
|
|||||||
|
|
||||||
extern kutil::heap_allocator g_kernel_heap;
|
extern kutil::heap_allocator g_kernel_heap;
|
||||||
|
|
||||||
|
class test_observer :
|
||||||
|
public kobject::observer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
test_observer(const char *name) : m_name(name) {}
|
||||||
|
|
||||||
|
virtual bool on_signals_changed(
|
||||||
|
kobject *obj,
|
||||||
|
j6_signal_t s,
|
||||||
|
j6_signal_t ds,
|
||||||
|
j6_status_t result)
|
||||||
|
{
|
||||||
|
log::info(logs::objs, " %s: Signals %016lx changed, object %p, result %016lx",
|
||||||
|
m_name, ds, obj, result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *m_name;
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
init_console()
|
init_console()
|
||||||
{
|
{
|
||||||
@@ -143,5 +167,20 @@ kernel_main(kernel_args *header)
|
|||||||
sched->load_process(f.name(), f.data(), f.size());
|
sched->load_process(f.name(), f.data(), f.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::info(logs::objs, "Testing object system:");
|
||||||
|
|
||||||
|
test_observer obs1("event");
|
||||||
|
test_observer obs2("no handles");
|
||||||
|
{
|
||||||
|
event e;
|
||||||
|
|
||||||
|
e.register_signal_observer(&obs1, j6_signal_user0);
|
||||||
|
e.register_signal_observer(&obs2, j6_signal_no_handles);
|
||||||
|
|
||||||
|
e.assert_signal(j6_signal_user0);
|
||||||
|
|
||||||
|
handle h(1, 0, &e);
|
||||||
|
}
|
||||||
|
|
||||||
sched->start();
|
sched->start();
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/kernel/objects/event.h
Normal file
15
src/kernel/objects/event.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file event.h
|
||||||
|
/// Definition of event kobject types
|
||||||
|
|
||||||
|
#include "objects/kobject.h"
|
||||||
|
|
||||||
|
class event :
|
||||||
|
public kobject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr type type_id = type::event;
|
||||||
|
|
||||||
|
event() :
|
||||||
|
kobject(type_id) {}
|
||||||
|
};
|
||||||
26
src/kernel/objects/handle.cpp
Normal file
26
src/kernel/objects/handle.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include "objects/handle.h"
|
||||||
|
|
||||||
|
handle::handle(handle&& other) :
|
||||||
|
m_owner(other.m_owner),
|
||||||
|
m_object(other.m_object),
|
||||||
|
m_rights(other.m_rights)
|
||||||
|
{
|
||||||
|
other.m_owner = 0;
|
||||||
|
other.m_object = nullptr;
|
||||||
|
other.m_rights = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle::handle(j6_koid_t owner, j6_rights_t rights, kobject *obj) :
|
||||||
|
m_owner(owner),
|
||||||
|
m_object(obj),
|
||||||
|
m_rights(rights)
|
||||||
|
{
|
||||||
|
if (m_object)
|
||||||
|
m_object->handle_retain();
|
||||||
|
}
|
||||||
|
|
||||||
|
handle::~handle()
|
||||||
|
{
|
||||||
|
if (m_object)
|
||||||
|
m_object->handle_release();
|
||||||
|
}
|
||||||
30
src/kernel/objects/handle.h
Normal file
30
src/kernel/objects/handle.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file handle.h
|
||||||
|
/// Defines types for user handles to kernel objects
|
||||||
|
|
||||||
|
#include "j6/types.h"
|
||||||
|
#include "objects/kobject.h"
|
||||||
|
|
||||||
|
class handle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Move constructor. Takes ownership of the object from other.
|
||||||
|
handle(handle&& other);
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
/// \arg owner koid of the process that has this handle
|
||||||
|
/// \arg rights access rights this handle has over the object
|
||||||
|
/// \arg obj the object held
|
||||||
|
handle(j6_koid_t owner, j6_rights_t rights, kobject *obj);
|
||||||
|
|
||||||
|
~handle();
|
||||||
|
|
||||||
|
handle() = delete;
|
||||||
|
handle(const handle &other) = delete;
|
||||||
|
handle & operator=(const handle& other) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
j6_koid_t m_owner;
|
||||||
|
kobject *m_object;
|
||||||
|
j6_rights_t m_rights;
|
||||||
|
};
|
||||||
98
src/kernel/objects/kobject.cpp
Normal file
98
src/kernel/objects/kobject.cpp
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include "j6/errors.h"
|
||||||
|
#include "j6/signals.h"
|
||||||
|
#include "j6/types.h"
|
||||||
|
#include "kutil/heap_allocator.h"
|
||||||
|
#include "objects/kobject.h"
|
||||||
|
|
||||||
|
extern kutil::heap_allocator g_kernel_heap;
|
||||||
|
|
||||||
|
// TODO: per-cpu this?
|
||||||
|
static j6_koid_t next_koid;
|
||||||
|
|
||||||
|
kobject::kobject(type t, j6_signal_t signals) :
|
||||||
|
m_koid(koid_generate(t)),
|
||||||
|
m_signals(signals),
|
||||||
|
m_observers(g_kernel_heap),
|
||||||
|
m_handle_count(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
kobject::~kobject()
|
||||||
|
{
|
||||||
|
notify_signal_observers(0, j6_status_destroyed);
|
||||||
|
}
|
||||||
|
|
||||||
|
j6_koid_t
|
||||||
|
kobject::koid_generate(type t)
|
||||||
|
{
|
||||||
|
return (static_cast<uint64_t>(t) << 48) | next_koid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
kobject::type
|
||||||
|
kobject::koid_type(j6_koid_t koid)
|
||||||
|
{
|
||||||
|
return static_cast<type>((koid >> 48) & 0xffffull);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kobject::assert_signal(j6_signal_t s)
|
||||||
|
{
|
||||||
|
m_signals |= s;
|
||||||
|
notify_signal_observers(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kobject::deassert_signal(j6_signal_t s)
|
||||||
|
{
|
||||||
|
m_signals &= ~s;
|
||||||
|
notify_signal_observers(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kobject::register_signal_observer(observer *object, j6_signal_t s)
|
||||||
|
{
|
||||||
|
m_observers.emplace(object, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kobject::deregister_signal_observer(observer *object)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_observers.count(); ++i) {
|
||||||
|
auto ® = m_observers[i];
|
||||||
|
if (reg.object != object) continue;
|
||||||
|
|
||||||
|
reg = m_observers[m_observers.count() - 1];
|
||||||
|
m_observers.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kobject::notify_signal_observers(j6_signal_t mask, j6_status_t result)
|
||||||
|
{
|
||||||
|
for (auto ® : m_observers) {
|
||||||
|
if (mask == 0 || (reg.signals & mask) != 0) {
|
||||||
|
if (!reg.object->on_signals_changed(this, m_signals, mask, result))
|
||||||
|
reg.object = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compact the observer list
|
||||||
|
long last = m_observers.count() - 1;
|
||||||
|
while (m_observers[last].object == nullptr && last >= 0) last--;
|
||||||
|
|
||||||
|
for (long i = 0; i < long(m_observers.count()) && i < last; ++i) {
|
||||||
|
auto ® = m_observers[i];
|
||||||
|
if (reg.object != nullptr) continue;
|
||||||
|
reg = m_observers[last--];
|
||||||
|
|
||||||
|
while (m_observers[last].object == nullptr && last >= i) last--;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_observers.set_size(last + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kobject::on_no_handles()
|
||||||
|
{
|
||||||
|
assert_signal(j6_signal_no_handles);
|
||||||
|
}
|
||||||
110
src/kernel/objects/kobject.h
Normal file
110
src/kernel/objects/kobject.h
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file kobject.h
|
||||||
|
/// Definition of base type for user-interactable kernel objects
|
||||||
|
|
||||||
|
#include "j6/errors.h"
|
||||||
|
#include "j6/types.h"
|
||||||
|
#include "kutil/vector.h"
|
||||||
|
|
||||||
|
/// Base type for all user-interactable kernel objects
|
||||||
|
class kobject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Types of kernel objects.
|
||||||
|
enum class type : uint16_t
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
|
||||||
|
event,
|
||||||
|
eventpair,
|
||||||
|
|
||||||
|
vms,
|
||||||
|
vmo,
|
||||||
|
|
||||||
|
job,
|
||||||
|
process,
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
|
kobject(type t, j6_signal_t signals = 0ull);
|
||||||
|
virtual ~kobject();
|
||||||
|
|
||||||
|
/// Generate a new koid for a given type
|
||||||
|
/// \arg t The object type
|
||||||
|
/// \returns A new unique koid
|
||||||
|
static j6_koid_t koid_generate(type t);
|
||||||
|
|
||||||
|
/// Get the kobject type from a given koid
|
||||||
|
/// \arg koid An existing koid
|
||||||
|
/// \returns The object type for the koid
|
||||||
|
static type koid_type(j6_koid_t koid);
|
||||||
|
|
||||||
|
/// Set the given signals active on this object
|
||||||
|
/// \arg s The set of signals to assert
|
||||||
|
void assert_signal(j6_signal_t s);
|
||||||
|
|
||||||
|
/// Clear the given signals on this object
|
||||||
|
/// \arg s The set of signals to deassert
|
||||||
|
void deassert_signal(j6_signal_t s);
|
||||||
|
|
||||||
|
class observer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Callback for when signals change.
|
||||||
|
/// \arg obj The object triggering the callback
|
||||||
|
/// \arg s The current state of obj's signals
|
||||||
|
/// \arg ds Which signals caused the callback
|
||||||
|
/// \arg result Status code for this notification
|
||||||
|
/// \returns True if this object wants to keep watching signals
|
||||||
|
virtual bool on_signals_changed(
|
||||||
|
kobject *obj,
|
||||||
|
j6_signal_t s,
|
||||||
|
j6_signal_t ds,
|
||||||
|
j6_status_t result) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Register a signal observer
|
||||||
|
/// \arg object The observer
|
||||||
|
/// \arg s The signals the object wants notifiations for
|
||||||
|
void register_signal_observer(observer *object, j6_signal_t s);
|
||||||
|
|
||||||
|
/// Deegister a signal observer
|
||||||
|
/// \arg object The observer
|
||||||
|
void deregister_signal_observer(observer *object);
|
||||||
|
|
||||||
|
/// Increment the handle refcount
|
||||||
|
inline void handle_retain() { ++m_handle_count; }
|
||||||
|
|
||||||
|
/// Decrement the handle refcount
|
||||||
|
inline void handle_release() {
|
||||||
|
if (--m_handle_count == 0) on_no_handles();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
kobject() = delete;
|
||||||
|
kobject(const kobject &other) = delete;
|
||||||
|
kobject(const kobject &&other) = delete;
|
||||||
|
|
||||||
|
/// Notifiy observers of this object
|
||||||
|
/// \arg mask The signals that triggered this call. If 0, notify all observers.
|
||||||
|
/// \arg result The result to pass to the observers
|
||||||
|
void notify_signal_observers(j6_signal_t mask, j6_status_t result = j6_status_ok);
|
||||||
|
|
||||||
|
/// Interface for subclasses to handle when all handles are closed. Subclasses
|
||||||
|
/// should either call the base version, or assert j6_signal_no_handles.
|
||||||
|
virtual void on_no_handles();
|
||||||
|
|
||||||
|
j6_koid_t m_koid;
|
||||||
|
j6_signal_t m_signals;
|
||||||
|
uint16_t m_handle_count;
|
||||||
|
|
||||||
|
struct observer_registration
|
||||||
|
{
|
||||||
|
observer_registration(observer* o = nullptr, j6_signal_t s = 0) :
|
||||||
|
object(o), signals(s) {}
|
||||||
|
|
||||||
|
observer *object;
|
||||||
|
j6_signal_t signals;
|
||||||
|
};
|
||||||
|
kutil::vector<observer_registration> m_observers;
|
||||||
|
};
|
||||||
@@ -117,12 +117,14 @@ public:
|
|||||||
m_elements[m_size].~T();
|
m_elements[m_size].~T();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the size of the array. Any new items are default
|
/// Set the size of the array. Any new items are default constructed.
|
||||||
/// constructed. The array is realloced if needed.
|
/// Any items past the end are deleted. The array is realloced if needed.
|
||||||
/// \arg size The new size
|
/// \arg size The new size
|
||||||
void set_size(size_t size)
|
void set_size(size_t size)
|
||||||
{
|
{
|
||||||
ensure_capacity(size);
|
ensure_capacity(size);
|
||||||
|
for (size_t i = size; i < m_size; ++i)
|
||||||
|
m_elements[i].~T();
|
||||||
for (size_t i = m_size; i < size; ++i)
|
for (size_t i = m_size; i < size; ++i)
|
||||||
new (&m_elements[i]) T;
|
new (&m_elements[i]) T;
|
||||||
m_size = size;
|
m_size = size;
|
||||||
|
|||||||
Reference in New Issue
Block a user