[kernel] Make channels stream based
Multiple changes regarding channels. Mainly channels are now stream based and can handle partial reads or writes. Channels now use the kernel buffers area with the related buffer_cache. Added a fake stdout stream channel and kernel task to read its contents to the screen in preparation for handing channels as stdin/stdout to processes.
This commit is contained in:
@@ -26,7 +26,8 @@ thread_proc()
|
|||||||
|
|
||||||
_syscall_system_log("sub thread signaled user0");
|
_syscall_system_log("sub thread signaled user0");
|
||||||
|
|
||||||
result = _syscall_channel_send(chan, sizeof(message), (void*)message);
|
size_t size = sizeof(message);
|
||||||
|
result = _syscall_channel_send(chan, &size, (void*)message);
|
||||||
if (result != j6_status_ok)
|
if (result != j6_status_ok)
|
||||||
_syscall_thread_exit(result);
|
_syscall_thread_exit(result);
|
||||||
|
|
||||||
|
|||||||
@@ -11,25 +11,34 @@ namespace memory {
|
|||||||
constexpr size_t frame_size = 0x1000;
|
constexpr size_t frame_size = 0x1000;
|
||||||
|
|
||||||
/// Start of kernel memory.
|
/// Start of kernel memory.
|
||||||
constexpr uintptr_t kernel_offset = 0xffff800000000000;
|
constexpr uintptr_t kernel_offset = 0xffff800000000000ull;
|
||||||
|
|
||||||
/// Offset from physical where page tables are mapped.
|
/// Offset from physical where page tables are mapped.
|
||||||
constexpr uintptr_t page_offset = 0xffffc00000000000;
|
constexpr uintptr_t page_offset = 0xffffc00000000000ull;
|
||||||
|
|
||||||
/// Number of pages for a kernel stack
|
/// Max number of pages for a kernel stack
|
||||||
constexpr unsigned kernel_stack_pages = 1;
|
constexpr unsigned kernel_stack_pages = 1;
|
||||||
|
|
||||||
|
/// Max number of pages for a kernel buffer
|
||||||
|
constexpr unsigned kernel_buffer_pages = 16;
|
||||||
|
|
||||||
/// Max size of the kernel heap
|
/// Max size of the kernel heap
|
||||||
constexpr size_t kernel_max_heap = 0x8000000000; // 512GiB
|
constexpr size_t kernel_max_heap = 0x8000000000ull; // 512GiB
|
||||||
|
|
||||||
/// Start of the kernel heap
|
/// Start of the kernel heap
|
||||||
constexpr uintptr_t heap_start = page_offset - kernel_max_heap;
|
constexpr uintptr_t heap_start = page_offset - kernel_max_heap;
|
||||||
|
|
||||||
/// Start of the kernel stacks
|
|
||||||
constexpr uintptr_t stacks_start = heap_start - kernel_max_heap;
|
|
||||||
|
|
||||||
/// Max size of the kernel stacks area
|
/// Max size of the kernel stacks area
|
||||||
constexpr size_t kernel_max_stacks = 0x8000000000; // 512GiB
|
constexpr size_t kernel_max_stacks = 0x8000000000ull; // 512GiB
|
||||||
|
|
||||||
|
/// Start of the kernel stacks
|
||||||
|
constexpr uintptr_t stacks_start = heap_start - kernel_max_stacks;
|
||||||
|
|
||||||
|
/// Max size of kernel buffers area
|
||||||
|
constexpr size_t kernel_max_buffers = 0x10000000000ull; // 1TiB
|
||||||
|
|
||||||
|
/// Start of kernel buffers
|
||||||
|
constexpr uintptr_t buffers_start = stacks_start - kernel_max_buffers;
|
||||||
|
|
||||||
/// First kernel space PML4 entry
|
/// First kernel space PML4 entry
|
||||||
constexpr unsigned pml4e_kernel = 256;
|
constexpr unsigned pml4e_kernel = 256;
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ SYSCALL(0x1c, thread_sleep, uint64_t)
|
|||||||
|
|
||||||
SYSCALL(0x20, channel_create, j6_handle_t *)
|
SYSCALL(0x20, channel_create, j6_handle_t *)
|
||||||
SYSCALL(0x21, channel_close, j6_handle_t)
|
SYSCALL(0x21, channel_close, j6_handle_t)
|
||||||
SYSCALL(0x22, channel_send, j6_handle_t, size_t, void *)
|
SYSCALL(0x22, channel_send, j6_handle_t, size_t *, void *)
|
||||||
SYSCALL(0x23, channel_receive, j6_handle_t, size_t *, void *)
|
SYSCALL(0x23, channel_receive, j6_handle_t, size_t *, void *)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "kernel_args.h"
|
#include "kernel_args.h"
|
||||||
#include "kernel_memory.h"
|
#include "kernel_memory.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "objects/channel.h"
|
||||||
#include "objects/event.h"
|
#include "objects/event.h"
|
||||||
#include "objects/handle.h"
|
#include "objects/handle.h"
|
||||||
#include "page_manager.h"
|
#include "page_manager.h"
|
||||||
@@ -49,28 +50,6 @@ void memory_initialize_post_ctors(kernel::args::header *kargs);
|
|||||||
|
|
||||||
using namespace kernel;
|
using namespace kernel;
|
||||||
|
|
||||||
/*
|
|
||||||
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()
|
||||||
{
|
{
|
||||||
@@ -84,6 +63,40 @@ init_console()
|
|||||||
logger_init();
|
logger_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel *std_out = nullptr;
|
||||||
|
|
||||||
|
void
|
||||||
|
stdout_task()
|
||||||
|
{
|
||||||
|
uint8_t buffer[257];
|
||||||
|
auto *ent = reinterpret_cast<log::logger::entry *>(buffer);
|
||||||
|
auto *cons = console::get();
|
||||||
|
|
||||||
|
log::info(logs::task, "Starting kernel stdout task");
|
||||||
|
|
||||||
|
scheduler &s = scheduler::get();
|
||||||
|
thread *th = thread::from_tcb(s.current());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
j6_signal_t current = std_out->signals();
|
||||||
|
if (!(current & j6_signal_channel_can_recv)) {
|
||||||
|
th->wait_on_signals(std_out, j6_signal_channel_can_recv);
|
||||||
|
s.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t n = 256;
|
||||||
|
j6_status_t status = std_out->dequeue(&n, buffer);
|
||||||
|
if (status != j6_status_ok) {
|
||||||
|
log::warn(logs::task, "Kernel stdout error: %x", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[n] = 0;
|
||||||
|
cons->puts(reinterpret_cast<const char *>(buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
kernel_main(args::header *header)
|
kernel_main(args::header *header)
|
||||||
{
|
{
|
||||||
@@ -190,22 +203,14 @@ kernel_main(args::header *header)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
std_out = new channel;
|
||||||
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->create_kernel_task(logger_task, scheduler::max_priority-1, true);
|
sched->create_kernel_task(logger_task, scheduler::max_priority-1, true);
|
||||||
|
sched->create_kernel_task(stdout_task, scheduler::max_priority-1, true);
|
||||||
|
|
||||||
|
const char stdout_message[] = "Hello on the fake stdout channel\n";
|
||||||
|
size_t message_size = sizeof(stdout_message);
|
||||||
|
std_out->enqueue(&message_size, reinterpret_cast<const void*>(stdout_message));
|
||||||
|
|
||||||
sched->start();
|
sched->start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using memory::frame_size;
|
|||||||
using memory::heap_start;
|
using memory::heap_start;
|
||||||
using memory::kernel_max_heap;
|
using memory::kernel_max_heap;
|
||||||
using memory::kernel_offset;
|
using memory::kernel_offset;
|
||||||
|
using memory::heap_start;
|
||||||
using memory::page_offset;
|
using memory::page_offset;
|
||||||
using memory::pml4e_kernel;
|
using memory::pml4e_kernel;
|
||||||
using memory::pml4e_offset;
|
using memory::pml4e_offset;
|
||||||
@@ -23,7 +24,7 @@ using memory::table_entries;
|
|||||||
|
|
||||||
using namespace kernel;
|
using namespace kernel;
|
||||||
|
|
||||||
kutil::vm_space g_kernel_space {kernel_offset, (page_offset-kernel_offset)};
|
kutil::vm_space g_kernel_space {kernel_offset, (heap_start-kernel_offset)};
|
||||||
|
|
||||||
|
|
||||||
// These objects are initialized _before_ global constructors are called,
|
// These objects are initialized _before_ global constructors are called,
|
||||||
|
|||||||
@@ -1,40 +1,49 @@
|
|||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
|
|
||||||
|
#include "buffer_cache.h"
|
||||||
|
#include "kernel_memory.h"
|
||||||
#include "objects/channel.h"
|
#include "objects/channel.h"
|
||||||
|
|
||||||
|
using memory::frame_size;
|
||||||
|
using memory::kernel_buffer_pages;
|
||||||
|
static constexpr size_t buffer_bytes = kernel_buffer_pages * frame_size;
|
||||||
|
|
||||||
channel::channel() :
|
channel::channel() :
|
||||||
m_len(0),
|
m_len(0),
|
||||||
m_capacity(0),
|
m_data(g_kbuffer_cache.get_buffer()),
|
||||||
m_data(nullptr),
|
m_buffer(reinterpret_cast<uint8_t*>(m_data), buffer_bytes),
|
||||||
kobject(kobject::type::channel, j6_signal_channel_can_send)
|
kobject(kobject::type::channel, j6_signal_channel_can_send)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
channel::~channel()
|
channel::~channel()
|
||||||
{
|
{
|
||||||
kutil::kfree(m_data);
|
if (!closed()) close();
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
channel::enqueue(size_t len, void *data)
|
channel::enqueue(size_t *len, const void *data)
|
||||||
{
|
{
|
||||||
// TODO: Make this thread safe!
|
// TODO: Make this thread safe!
|
||||||
if (closed())
|
if (closed())
|
||||||
return j6_status_closed;
|
return j6_status_closed;
|
||||||
|
|
||||||
if (!can_send())
|
if (!len || !*len)
|
||||||
|
return j6_err_invalid_arg;
|
||||||
|
|
||||||
|
if (m_buffer.free_space() == 0)
|
||||||
return j6_err_not_ready;
|
return j6_err_not_ready;
|
||||||
|
|
||||||
if (m_capacity < len) {
|
void *buffer = nullptr;
|
||||||
kutil::kfree(m_data);
|
size_t avail = m_buffer.reserve(*len, &buffer);
|
||||||
m_data = kutil::kalloc(len);
|
*len = *len > avail ? avail : *len;
|
||||||
m_capacity = len;
|
|
||||||
kassert(m_data, "Failed to allocate memory to copy channel message");
|
kutil::memcpy(buffer, data, *len);
|
||||||
}
|
m_buffer.commit(*len);
|
||||||
|
|
||||||
m_len = len;
|
|
||||||
kutil::memcpy(m_data, data, len);
|
|
||||||
assert_signal(j6_signal_channel_can_recv);
|
assert_signal(j6_signal_channel_can_recv);
|
||||||
|
if (m_buffer.free_space() == 0)
|
||||||
|
deassert_signal(j6_signal_channel_can_send);
|
||||||
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
@@ -46,22 +55,33 @@ channel::dequeue(size_t *len, void *data)
|
|||||||
if (closed())
|
if (closed())
|
||||||
return j6_status_closed;
|
return j6_status_closed;
|
||||||
|
|
||||||
if (!can_receive())
|
if (!len || !*len)
|
||||||
return j6_err_not_ready;
|
|
||||||
|
|
||||||
if (!len)
|
|
||||||
return j6_err_invalid_arg;
|
return j6_err_invalid_arg;
|
||||||
|
|
||||||
if (*len < m_len)
|
if (m_buffer.size() == 0)
|
||||||
return j6_err_insufficient;
|
return j6_err_not_ready;
|
||||||
|
|
||||||
|
void *buffer = nullptr;
|
||||||
|
size_t avail = m_buffer.get_block(&buffer);
|
||||||
|
*len = *len > avail ? avail : *len;
|
||||||
|
|
||||||
|
kutil::memcpy(data, buffer, *len);
|
||||||
|
m_buffer.consume(*len);
|
||||||
|
|
||||||
kutil::memcpy(data, m_data, m_len);
|
|
||||||
*len = m_len;
|
|
||||||
assert_signal(j6_signal_channel_can_send);
|
assert_signal(j6_signal_channel_can_send);
|
||||||
|
if (m_buffer.size() == 0)
|
||||||
|
deassert_signal(j6_signal_channel_can_recv);
|
||||||
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
channel::close()
|
||||||
|
{
|
||||||
|
g_kbuffer_cache.return_buffer(m_data);
|
||||||
|
assert_signal(j6_signal_channel_closed);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
channel::on_no_handles()
|
channel::on_no_handles()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
/// Definition of channel objects and related functions
|
/// Definition of channel objects and related functions
|
||||||
|
|
||||||
#include "j6/signals.h"
|
#include "j6/signals.h"
|
||||||
|
#include "kutil/bip_buffer.h"
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
|
|
||||||
/// Channels are bi-directional means of sending messages
|
/// Channels are bi-directional means of sending messages
|
||||||
@@ -20,10 +21,10 @@ public:
|
|||||||
inline bool can_receive() const { return check_signal(j6_signal_channel_can_recv); }
|
inline bool can_receive() const { return check_signal(j6_signal_channel_can_recv); }
|
||||||
|
|
||||||
/// Put a message into the channel
|
/// Put a message into the channel
|
||||||
/// \arg len Length of data, in bytes
|
/// \arg len [in] Bytes in data buffer [out] number of bytes written
|
||||||
/// \arg data Pointer to the message data
|
/// \arg data Pointer to the message data
|
||||||
/// \returns j6_status_ok on success
|
/// \returns j6_status_ok on success
|
||||||
j6_status_t enqueue(size_t len, void *data);
|
j6_status_t enqueue(size_t *len, const void *data);
|
||||||
|
|
||||||
/// Get a message from the channel, copied into a provided buffer
|
/// Get a message from the channel, copied into a provided buffer
|
||||||
/// \arg len On input, the size of the provided buffer. On output,
|
/// \arg len On input, the size of the provided buffer. On output,
|
||||||
@@ -34,7 +35,7 @@ public:
|
|||||||
|
|
||||||
/// Mark this channel as closed, all future calls to enqueue or
|
/// Mark this channel as closed, all future calls to enqueue or
|
||||||
/// dequeue messages will fail with j6_status_closed.
|
/// dequeue messages will fail with j6_status_closed.
|
||||||
inline void close() { assert_signal(j6_signal_channel_closed); }
|
void close();
|
||||||
|
|
||||||
/// Check if this channel has been closed
|
/// Check if this channel has been closed
|
||||||
inline bool closed() { return check_signal(j6_signal_channel_closed); }
|
inline bool closed() { return check_signal(j6_signal_channel_closed); }
|
||||||
@@ -44,6 +45,6 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
size_t m_len;
|
size_t m_len;
|
||||||
size_t m_capacity;
|
uintptr_t m_data;
|
||||||
void *m_data;
|
kutil::bip_buffer m_buffer;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ channel_close(j6_handle_t handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
channel_send(j6_handle_t handle, size_t len, void *data)
|
channel_send(j6_handle_t handle, size_t *len, void *data)
|
||||||
{
|
{
|
||||||
scheduler &s = scheduler::get();
|
scheduler &s = scheduler::get();
|
||||||
TCB *tcb = s.current();
|
TCB *tcb = s.current();
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ struct vm_range
|
|||||||
vm_state state;
|
vm_state state;
|
||||||
|
|
||||||
inline uintptr_t end() const { return address + size; }
|
inline uintptr_t end() const { return address + size; }
|
||||||
inline int compare(const vm_range *other) const {
|
inline int64_t compare(const vm_range *other) const {
|
||||||
return other->address - address;
|
if (address > other->address) return -1;
|
||||||
|
else if (address < other->address) return 1;
|
||||||
|
else return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ vm_space::commit(uintptr_t start, size_t size)
|
|||||||
vm_state
|
vm_state
|
||||||
vm_space::get(uintptr_t addr)
|
vm_space::get(uintptr_t addr)
|
||||||
{
|
{
|
||||||
node_type *node = find_overlapping(m_ranges.root(), addr, 0);
|
node_type *node = find_overlapping(m_ranges.root(), addr, 1);
|
||||||
return node ? node->state : vm_state::unknown;
|
return node ? node->state : vm_state::unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user