diff --git a/src/drivers/nulldrv/main.cpp b/src/drivers/nulldrv/main.cpp index 73afacb..fdda149 100644 --- a/src/drivers/nulldrv/main.cpp +++ b/src/drivers/nulldrv/main.cpp @@ -26,7 +26,8 @@ thread_proc() _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) _syscall_thread_exit(result); diff --git a/src/include/kernel_memory.h b/src/include/kernel_memory.h index 32ffccf..07709a9 100644 --- a/src/include/kernel_memory.h +++ b/src/include/kernel_memory.h @@ -11,25 +11,34 @@ namespace memory { constexpr size_t frame_size = 0x1000; /// Start of kernel memory. - constexpr uintptr_t kernel_offset = 0xffff800000000000; + constexpr uintptr_t kernel_offset = 0xffff800000000000ull; /// 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; + /// Max number of pages for a kernel buffer + constexpr unsigned kernel_buffer_pages = 16; + /// 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 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 - 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 constexpr unsigned pml4e_kernel = 256; diff --git a/src/include/syscalls.inc b/src/include/syscalls.inc index c0e0c83..5f14f00 100644 --- a/src/include/syscalls.inc +++ b/src/include/syscalls.inc @@ -15,5 +15,5 @@ SYSCALL(0x1c, thread_sleep, uint64_t) SYSCALL(0x20, channel_create, 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 *) diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index cd74779..91d0c21 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -17,6 +17,7 @@ #include "kernel_args.h" #include "kernel_memory.h" #include "log.h" +#include "objects/channel.h" #include "objects/event.h" #include "objects/handle.h" #include "page_manager.h" @@ -49,28 +50,6 @@ void memory_initialize_post_ctors(kernel::args::header *kargs); 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 init_console() { @@ -84,6 +63,40 @@ init_console() logger_init(); } +channel *std_out = nullptr; + +void +stdout_task() +{ + uint8_t buffer[257]; + auto *ent = reinterpret_cast(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(buffer)); + } +} + + void kernel_main(args::header *header) { @@ -190,22 +203,14 @@ kernel_main(args::header *header) } } - /* - 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); - } - */ + std_out = new channel; 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(stdout_message)); + sched->start(); } diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 0fec758..58fc39b 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -16,6 +16,7 @@ using memory::frame_size; using memory::heap_start; using memory::kernel_max_heap; using memory::kernel_offset; +using memory::heap_start; using memory::page_offset; using memory::pml4e_kernel; using memory::pml4e_offset; @@ -23,7 +24,7 @@ using memory::table_entries; 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, diff --git a/src/kernel/objects/channel.cpp b/src/kernel/objects/channel.cpp index 6f5d4e6..9428adb 100644 --- a/src/kernel/objects/channel.cpp +++ b/src/kernel/objects/channel.cpp @@ -1,40 +1,49 @@ #include "kutil/assert.h" +#include "buffer_cache.h" +#include "kernel_memory.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() : m_len(0), - m_capacity(0), - m_data(nullptr), + m_data(g_kbuffer_cache.get_buffer()), + m_buffer(reinterpret_cast(m_data), buffer_bytes), kobject(kobject::type::channel, j6_signal_channel_can_send) { } channel::~channel() { - kutil::kfree(m_data); + if (!closed()) close(); } j6_status_t -channel::enqueue(size_t len, void *data) +channel::enqueue(size_t *len, const void *data) { // TODO: Make this thread safe! if (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; - if (m_capacity < len) { - kutil::kfree(m_data); - m_data = kutil::kalloc(len); - m_capacity = len; - kassert(m_data, "Failed to allocate memory to copy channel message"); - } + void *buffer = nullptr; + size_t avail = m_buffer.reserve(*len, &buffer); + *len = *len > avail ? avail : *len; + + 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); + if (m_buffer.free_space() == 0) + deassert_signal(j6_signal_channel_can_send); return j6_status_ok; } @@ -46,22 +55,33 @@ channel::dequeue(size_t *len, void *data) if (closed()) return j6_status_closed; - if (!can_receive()) - return j6_err_not_ready; - - if (!len) + if (!len || !*len) return j6_err_invalid_arg; - if (*len < m_len) - return j6_err_insufficient; + if (m_buffer.size() == 0) + 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); + if (m_buffer.size() == 0) + deassert_signal(j6_signal_channel_can_recv); return j6_status_ok; } +void +channel::close() +{ + g_kbuffer_cache.return_buffer(m_data); + assert_signal(j6_signal_channel_closed); +} + void channel::on_no_handles() { diff --git a/src/kernel/objects/channel.h b/src/kernel/objects/channel.h index 0d00495..d381d84 100644 --- a/src/kernel/objects/channel.h +++ b/src/kernel/objects/channel.h @@ -3,6 +3,7 @@ /// Definition of channel objects and related functions #include "j6/signals.h" +#include "kutil/bip_buffer.h" #include "objects/kobject.h" /// 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); } /// 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 /// \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 /// \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 /// 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 inline bool closed() { return check_signal(j6_signal_channel_closed); } @@ -44,6 +45,6 @@ protected: private: size_t m_len; - size_t m_capacity; - void *m_data; + uintptr_t m_data; + kutil::bip_buffer m_buffer; }; diff --git a/src/kernel/syscalls/channel.cpp b/src/kernel/syscalls/channel.cpp index 0b6bd21..90881f0 100644 --- a/src/kernel/syscalls/channel.cpp +++ b/src/kernel/syscalls/channel.cpp @@ -42,7 +42,7 @@ channel_close(j6_handle_t handle) } 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(); TCB *tcb = s.current(); diff --git a/src/libraries/kutil/include/kutil/vm_space.h b/src/libraries/kutil/include/kutil/vm_space.h index 8a6bf88..48e7442 100644 --- a/src/libraries/kutil/include/kutil/vm_space.h +++ b/src/libraries/kutil/include/kutil/vm_space.h @@ -22,8 +22,10 @@ struct vm_range vm_state state; inline uintptr_t end() const { return address + size; } - inline int compare(const vm_range *other) const { - return other->address - address; + inline int64_t compare(const vm_range *other) const { + if (address > other->address) return -1; + else if (address < other->address) return 1; + else return 0; } }; diff --git a/src/libraries/kutil/vm_space.cpp b/src/libraries/kutil/vm_space.cpp index 07d11a6..47c8b5b 100644 --- a/src/libraries/kutil/vm_space.cpp +++ b/src/libraries/kutil/vm_space.cpp @@ -253,7 +253,7 @@ vm_space::commit(uintptr_t start, size_t size) vm_state 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; }