diff --git a/assets/manifests/minimal.yaml b/assets/manifests/minimal.yaml new file mode 100644 index 0000000..00e0e0d --- /dev/null +++ b/assets/manifests/minimal.yaml @@ -0,0 +1,14 @@ +--- +location: jsix +init: srv.init +initrd: + name: initrd.dat + format: zstd +panic: + - panic.serial +services: + - srv.logger +drivers: + - drv.uart +libs: + - ld.so diff --git a/assets/manifests/shell.yaml b/assets/manifests/shell.yaml new file mode 100644 index 0000000..51284d9 --- /dev/null +++ b/assets/manifests/shell.yaml @@ -0,0 +1,14 @@ +--- +location: jsix +init: srv.init +initrd: + name: initrd.dat + format: zstd +panic: + - panic.serial +services: + - 6s +drivers: + - drv.uart +libs: + - ld.so diff --git a/definitions/objects/mailbox.def b/definitions/objects/mailbox.def index ef0216f..eaa08b9 100644 --- a/definitions/objects/mailbox.def +++ b/definitions/objects/mailbox.def @@ -20,8 +20,9 @@ object mailbox : object { method call [cap:send] { param tag uint64 [inout] param data buffer [optional inout] - param data_in_len size # number of bytes in data used for input + param data_size size # number of total bytes in data buffer param handles ref object [optional inout handle list] + param handles_size size # total size of handles buffer } # Respond to a message sent using call, and wait for another @@ -31,8 +32,9 @@ object mailbox : object { method respond [cap:receive] { param tag uint64 [inout] param data buffer [optional inout] - param data_in_len size # number of bytes in data used for input + param data_size size # number of total bytes in data buffer param handles ref object [optional inout handle list] + param handles_size size # total size of handles buffer param reply_tag uint64 [inout] param flags uint64 } diff --git a/src/kernel/ipc_message.cpp b/src/kernel/ipc_message.cpp index 0895caf..ec16725 100644 --- a/src/kernel/ipc_message.cpp +++ b/src/kernel/ipc_message.cpp @@ -1,49 +1,142 @@ #include #include +#include "kassert.h" #include "ipc_message.h" +#include "j6/types.h" namespace ipc { -message::message() : tag {0}, data {nullptr, 0}, handles {nullptr, 0} {} +message::message() : tag {0}, data_size {0}, handle_count {0}, out_of_band {0} {} + message::message( uint64_t in_tag, const util::buffer &in_data, const util::counted &in_handles) : - tag {in_tag}, data {nullptr, in_data.count}, handles {nullptr, in_handles.count} + out_of_band {0} { - if (data.count) { - data.pointer = new uint8_t [data.count]; - memcpy(data.pointer, in_data.pointer, data.count); - } - - if (handles.count) { - handles.pointer = new j6_handle_t [handles.count]; - memcpy(handles.pointer, in_handles.pointer, handles.count * sizeof(j6_handle_t)); - } + set(in_tag, in_data, in_handles); +} + + +message::message(message &&other) { + *this = util::move(other); } -message::message(message &&other) { *this = util::move(other); } message::~message() { - delete [] reinterpret_cast(data.pointer); - delete [] handles.pointer; + clear_oob(); } + +util::buffer +message::data() +{ + uint8_t *buf = content + (handle_count * sizeof(j6_handle_t)); + if (out_of_band) + buf = reinterpret_cast(content)[handle_count]; + + return { + .pointer = buf, + .count = data_size, + }; +} + + +util::const_buffer +message::data() const +{ + const uint8_t *buf = content + (handle_count * sizeof(j6_handle_t)); + if (out_of_band) + buf = reinterpret_cast(content)[handle_count]; + + return { + .pointer = buf, + .count = data_size, + }; +} + + +util::counted +message::handles() +{ + return { + .pointer = reinterpret_cast(content), + .count = handle_count, + }; +} + + +util::counted +message::handles() const +{ + return { + .pointer = reinterpret_cast(content), + .count = data_size, + }; +} + + message & message::operator=(message &&other) { + clear_oob(); + tag = other.tag; other.tag = 0; - data = other.data; - other.data = {nullptr, 0}; + data_size = other.data_size; + other.data_size = 0; - handles = other.handles; - other.handles = {nullptr, 0}; + handle_count = other.handle_count; + other.handle_count = 0; + + out_of_band = other.out_of_band; + other.out_of_band = 0; + + memcpy(content, other.content, sizeof(content)); return *this; } -} // namespace ipc \ No newline at end of file + +void +message::set( + uint64_t in_tag, + const util::buffer &in_data, + const util::counted &in_handles) +{ + clear_oob(); + tag = in_tag; + handle_count = in_handles.count; + data_size = in_data.count; + + if (in_handles.count) { + kassert(in_handles.count < (sizeof(content) / sizeof(j6_handle_t)) - sizeof(void*)); + util::counted handlebuf = handles(); + memcpy(handlebuf.pointer, in_handles.pointer, handlebuf.count * sizeof(j6_handle_t)); + } + + if (in_data.count) { + if (in_data.count > sizeof(content) - (handle_count * sizeof(j6_handle_t))) { + out_of_band = 1; + auto *buf = new uint8_t [in_data.count]; + reinterpret_cast(content)[handle_count] = buf; + } + util::buffer databuf = data(); + memcpy(databuf.pointer, in_data.pointer, databuf.count); + } +} + + +void +message::clear_oob() +{ + if (out_of_band) { + uint8_t *buf = reinterpret_cast(content)[handle_count]; + delete [] buf; + } +} + +} // namespace ipc diff --git a/src/kernel/ipc_message.h b/src/kernel/ipc_message.h index e15f746..9dd5305 100644 --- a/src/kernel/ipc_message.h +++ b/src/kernel/ipc_message.h @@ -5,14 +5,29 @@ #include #include #include +#include namespace ipc { +static constexpr size_t message_size = 64; + struct message { uint64_t tag; - util::buffer data; - util::counted handles; + uint16_t data_size; + + uint16_t handle_count : 4; + uint16_t out_of_band : 1; + + uint32_t _reserved; + + uint8_t content[ message_size - 8 ]; + + util::buffer data(); + util::const_buffer data() const; + + util::counted handles(); + util::counted handles() const; message(); message(uint64_t in_tag, const util::buffer &in_data, const util::counted &in_handles); @@ -20,6 +35,13 @@ struct message ~message(); message & operator=(message &&other); + + void set(uint64_t in_tag, const util::buffer &in_data, const util::counted &in_handles); + +private: + void clear_oob(); }; -} // namespace ipc \ No newline at end of file +using message_ptr = util::unique_ptr; + +} // namespace ipc diff --git a/src/kernel/kernel_main.cpp b/src/kernel/kernel_main.cpp index 695723c..de4cfe7 100644 --- a/src/kernel/kernel_main.cpp +++ b/src/kernel/kernel_main.cpp @@ -1,4 +1,3 @@ -#include #include #include diff --git a/src/kernel/objects/mailbox.cpp b/src/kernel/objects/mailbox.cpp index 8423b8e..55157fb 100644 --- a/src/kernel/objects/mailbox.cpp +++ b/src/kernel/objects/mailbox.cpp @@ -60,7 +60,7 @@ mailbox::call() } j6_status_t -mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block) +mailbox::receive(ipc::message_ptr &data, reply_tag_t &reply_tag, bool block) { if (closed()) return j6_status_closed; @@ -68,7 +68,6 @@ mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block) thread ¤t = thread::current(); thread *caller = nullptr; - while (true) { caller = m_callers.pop_next(); if (caller) @@ -86,7 +85,6 @@ mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block) return s; } - util::scoped_lock lock {m_reply_lock}; reply_tag = ++m_next_reply_tag; m_reply_map.insert({ reply_tag, caller }); @@ -100,7 +98,7 @@ mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block) } j6_status_t -mailbox::reply(reply_tag_t reply_tag, ipc::message &&data) +mailbox::reply(reply_tag_t reply_tag, ipc::message_ptr data) { if (closed()) return j6_status_closed; diff --git a/src/kernel/objects/mailbox.h b/src/kernel/objects/mailbox.h index cf15b54..a0db691 100644 --- a/src/kernel/objects/mailbox.h +++ b/src/kernel/objects/mailbox.h @@ -22,7 +22,6 @@ class mailbox : public kobject { public: - using reply_tag_t = uint64_t; /// Capabilities on a newly constructed mailbox handle @@ -48,18 +47,18 @@ public: j6_status_t call(); /// Receive the next available message, optionally blocking if no messages are available. - /// \arg data [out] an ipc::message structure to fill + /// \arg data [out] the message /// \arg reply_tag [out] the reply_tag to use when replying to this message /// \arg block True if this call should block when no messages are available. /// \returns j6_status_ok if a message was received - j6_status_t receive(ipc::message &data, reply_tag_t &reply_tag, bool block); + j6_status_t receive(ipc::message_ptr &data, reply_tag_t &reply_tag, bool block); /// Find a given pending message to be responded to. Returns a replyer object, which will /// wake the calling read upon destruction. /// \arg reply_tag The reply tag in the original message /// \arg data Message data to pass on to the caller /// \returns j6_status_ok if the reply was successfully sent - j6_status_t reply(reply_tag_t reply_tag, ipc::message &&data); + j6_status_t reply(reply_tag_t reply_tag, ipc::message_ptr data); private: wait_queue m_callers; diff --git a/src/kernel/objects/thread.cpp b/src/kernel/objects/thread.cpp index 2f4cc4a..4939254 100644 --- a/src/kernel/objects/thread.cpp +++ b/src/kernel/objects/thread.cpp @@ -111,9 +111,6 @@ thread::wake_only() set_state(state::ready); } -void thread::set_message_data(ipc::message &&md) { m_message = util::move(md); } -ipc::message && thread::get_message_data() { return util::move(m_message); } - void thread::exit() { diff --git a/src/kernel/objects/thread.h b/src/kernel/objects/thread.h index e819eea..340b4ab 100644 --- a/src/kernel/objects/thread.h +++ b/src/kernel/objects/thread.h @@ -121,8 +121,8 @@ public: /// \returns The clock time at which to wake. 0 for no timeout. inline uint64_t wake_timeout() const { return m_wake_timeout; } - void set_message_data(ipc::message &&md); - ipc::message && get_message_data(); + inline void set_message_data(ipc::message_ptr md) { m_message = util::move(md); } + inline ipc::message_ptr get_message_data() { return util::move(m_message); } inline bool has_state(state s) const { return __atomic_load_n(reinterpret_cast(&m_state), __ATOMIC_ACQUIRE) & @@ -196,7 +196,7 @@ private: uint64_t m_wake_value; uint64_t m_wake_timeout; - ipc::message m_message; + ipc::message_ptr m_message; wait_queue m_join_queue; }; diff --git a/src/kernel/syscalls/mailbox.cpp b/src/kernel/syscalls/mailbox.cpp index dc5729c..bbf707b 100644 --- a/src/kernel/syscalls/mailbox.cpp +++ b/src/kernel/syscalls/mailbox.cpp @@ -35,16 +35,17 @@ mailbox_call( uint64_t *tag, void *in_data, size_t *data_len, - size_t data_in_len, + size_t data_size, j6_handle_t *in_handles, - size_t *handles_count) + size_t *handles_count, + size_t handles_size) { thread &cur = thread::current(); - util::buffer data {in_data, data_in_len}; + util::buffer data {in_data, *data_len}; util::counted handles {in_handles, *handles_count}; - ipc::message message(*tag, data, handles); + ipc::message_ptr message = new ipc::message {*tag, data, handles}; cur.set_message_data(util::move(message)); j6_status_t s = self->call(); @@ -52,19 +53,20 @@ mailbox_call( return s; message = cur.get_message_data(); + util::counted msg_handles = message->handles(); + util::buffer msg_data = message->data(); - if (message.handles) { - for (unsigned i = 0; i < message.handles.count; ++i) - process::current().add_handle(message.handles[i]); + if (message->handle_count) { + for (unsigned i = 0; i < msg_handles.count; ++i) + process::current().add_handle(msg_handles[i]); } - *tag = message.tag; - *data_len = *data_len > message.data.count ? message.data.count : *data_len; - memcpy(in_data, message.data.pointer, *data_len); + *tag = message->tag; + *data_len = data_size > msg_data.count ? msg_data.count : data_size; + memcpy(in_data, msg_data.pointer, *data_len); - size_t handles_min = *handles_count > message.handles.count ? message.handles.count : *handles_count; - *handles_count = handles_min; - memcpy(in_handles, message.handles.pointer, handles_min * sizeof(j6_handle_t)); + *handles_count = handles_size > msg_handles.count ? msg_handles.count : handles_size; + memcpy(in_handles, msg_handles.pointer, *handles_count * sizeof(j6_handle_t)); return j6_status_ok; } @@ -75,18 +77,20 @@ mailbox_respond( uint64_t *tag, void *in_data, size_t *data_len, - size_t data_in_len, + size_t data_size, j6_handle_t *in_handles, size_t *handles_count, + size_t handles_size, uint64_t *reply_tag, uint64_t flags) { - util::buffer data {in_data, data_in_len}; + util::buffer data {in_data, *data_len}; util::counted handles {in_handles, *handles_count}; - ipc::message message(*tag, data, handles); + ipc::message_ptr message; if (*reply_tag) { + message = new ipc::message {*tag, data, handles}; j6_status_t s = self->reply(*reply_tag, util::move(message)); if (s != j6_status_ok) return s; @@ -97,18 +101,20 @@ mailbox_respond( if (s != j6_status_ok) return s; - if (message.handles) { - for (unsigned i = 0; i < message.handles.count; ++i) - process::current().add_handle(message.handles[i]); + util::counted msg_handles = message->handles(); + util::buffer msg_data = message->data(); + + if (msg_handles) { + for (unsigned i = 0; i < msg_handles.count; ++i) + process::current().add_handle(msg_handles[i]); } - *tag = message.tag; - *data_len = *data_len > message.data.count ? message.data.count : *data_len; - memcpy(in_data, message.data.pointer, *data_len); + *tag = message->tag; + *data_len = data_size > msg_data.count ? msg_data.count : data_size; + memcpy(in_data, msg_data.pointer, *data_len); - size_t handles_min = *handles_count > message.handles.count ? message.handles.count : *handles_count; - *handles_count = handles_min; - memcpy(in_handles, message.handles.pointer, handles_min * sizeof(j6_handle_t)); + *handles_count = handles_size > msg_handles.count ? msg_handles.count : handles_size; + memcpy(in_handles, msg_handles.pointer, *handles_count * sizeof(j6_handle_t)); return j6_status_ok; } diff --git a/src/libraries/j6/channel.cpp b/src/libraries/j6/channel.cpp index 3896eb7..4f7e923 100644 --- a/src/libraries/j6/channel.cpp +++ b/src/libraries/j6/channel.cpp @@ -12,138 +12,177 @@ #include #include #include +#include +#include namespace j6 { -static uintptr_t channel_addr = 0x6000'0000; -static util::spinlock addr_spinlock; - -struct channel::header +struct channel_memory_area { - size_t size; - size_t read_index; - size_t write_index; - - mutex mutex; - condition read_waiting; - condition write_waiting; - - uint8_t data[0]; - - inline const void* read_at() const { return &data[read_index & (size - 1)]; } - inline void* write_at() { return &data[write_index & (size - 1)]; } - - inline size_t read_avail() const { return write_index - read_index; } - inline size_t write_avail() const { return size - read_avail(); } - - inline void consume(size_t n) { read_index += n; } - inline void commit(size_t n) { write_index += n; } + j6::mutex mutex; + j6::condition waiting; + util::bip_buffer buf; }; -channel * -channel::create(size_t size) + +static bool +check_channel_size(size_t s) { - j6_status_t result; - j6_handle_t vma = j6_handle_invalid; - - if (size < arch::frame_size || (size & (size - 1)) != 0) { - syslog(j6::logs::ipc, j6::log_level::error, "Bad channel size: %lx", size); - return nullptr; + if (s < arch::frame_size || (s & (s - 1)) != 0) { + syslog(j6::logs::ipc, j6::log_level::error, "Bad channel size: %lx", s); + return false; } + return true; +} - util::scoped_lock lock {addr_spinlock}; - uintptr_t addr = channel_addr; - channel_addr += size * 2; // account for ring buffer virtual space doubling - lock.release(); - result = j6_vma_create_map(&vma, size, &addr, j6_vm_flag_write|j6_vm_flag_ring); +static uintptr_t +create_channel_vma(j6_handle_t &vma, size_t size) +{ + uintptr_t addr = 0; + j6_status_t result = j6_vma_create_map(&vma, size, &addr, j6_vm_flag_write); if (result != j6_status_ok) { syslog(j6::logs::ipc, j6::log_level::error, "Failed to create channel VMA. Error: %lx", result); + return 0; + } + syslog(j6::logs::ipc, j6::log_level::verbose, "Created channel VMA at 0x%lx size 0x%lx", addr, size); + return addr; +} + + +static void +init_channel_memory_area(channel_memory_area *area, size_t size) +{ + new (&area->mutex) j6::mutex; + new (&area->waiting) j6::condition; + new (&area->buf) util::bip_buffer {size - sizeof(*area)}; +} + + +channel * +channel::create(size_t tx_size, size_t rx_size) +{ + if (!rx_size) + rx_size = tx_size; + + if (!check_channel_size(tx_size) || !check_channel_size(rx_size)) + return nullptr; + + j6_status_t result; + j6_handle_t tx_vma = j6_handle_invalid; + j6_handle_t rx_vma = j6_handle_invalid; + + uintptr_t tx_addr = create_channel_vma(tx_vma, tx_size); + if (!tx_addr) + return nullptr; + + uintptr_t rx_addr = create_channel_vma(rx_vma, rx_size); + if (!rx_addr) { + j6_vma_unmap(tx_vma, 0); + // TODO: Close TX handle return nullptr; } - header *h = reinterpret_cast(addr); - memset(h, 0, sizeof(*h)); - h->size = size; + channel_memory_area *tx = reinterpret_cast(tx_addr); + channel_memory_area *rx = reinterpret_cast(rx_addr); + init_channel_memory_area(tx, tx_size); + init_channel_memory_area(rx, rx_size); - return new channel {vma, h}; + j6::syslog(logs::ipc, log_level::info, "Created new channel with handles {%x, %x}", tx_vma, rx_vma); + + return new channel {{tx_vma, rx_vma}, *tx, *rx}; } channel * -channel::open(j6_handle_t vma) +channel::open(const channel_def &def) { j6_status_t result; - util::scoped_lock lock {addr_spinlock}; - uintptr_t addr = channel_addr; - - result = j6_vma_map(vma, 0, &addr, 0); + uintptr_t tx_addr = 0; + result = j6_vma_map(def.tx, 0, &tx_addr, 0); if (result != j6_status_ok) { syslog(j6::logs::ipc, j6::log_level::error, "Failed to map channel VMA. Error: %lx", result); return nullptr; } - header *h = reinterpret_cast(addr); - channel_addr += h->size; - lock.release(); + uintptr_t rx_addr = 0; + result = j6_vma_map(def.rx, 0, &rx_addr, 0); + if (result != j6_status_ok) { + j6_vma_unmap(def.tx, 0); + // TODO: Close TX handle + syslog(j6::logs::ipc, j6::log_level::error, "Failed to map channel VMA. Error: %lx", result); + return nullptr; + } - return new channel {vma, h}; + channel_memory_area *tx = reinterpret_cast(tx_addr); + channel_memory_area *rx = reinterpret_cast(rx_addr); + + j6::syslog(logs::ipc, log_level::info, "Opening existing channel with handles {%x:0x%lx, %x:0x%lx}", def.tx, tx, def.rx, rx); + return new channel { def, *tx, *rx }; } -channel::channel(j6_handle_t vma, header *h) : - m_vma {vma}, - m_size {h->size}, - m_header {h} +channel::channel( + const channel_def &def, + channel_memory_area &tx, + channel_memory_area &rx) : + m_def {def}, + m_tx {tx}, + m_rx {rx} { } -j6_status_t -channel::send(const void *buffer, size_t len, bool block) + +size_t +channel::reserve(size_t size, uint8_t **area, bool block) { - if (len > m_header->size) + if (size > m_tx.buf.buffer_size()) return j6_err_insufficient; - j6::scoped_lock lock {m_header->mutex}; - while (m_header->write_avail() < len) { - if (!block) - return j6_status_would_block; - + j6::scoped_lock lock {m_tx.mutex}; + while (m_tx.buf.write_available() < size) { + if (!block) return 0; lock.release(); - m_header->write_waiting.wait(); + m_tx.waiting.wait(); lock.acquire(); } - memcpy(m_header->write_at(), buffer, len); - m_header->commit(len); - m_header->read_waiting.wake(); - - return j6_status_ok; + return m_tx.buf.reserve(size, area); } -j6_status_t -channel::receive(void *buffer, size_t *size, bool block) +void +channel::commit(size_t size) { - j6::scoped_lock lock {m_header->mutex}; - while (!m_header->read_avail()) { - if (!block) { - *size = 0; - return j6_status_would_block; - } + j6::syslog(logs::ipc, log_level::spam, + "Sending %d bytes to channel on {%x}", size, m_def.tx); + j6::scoped_lock lock {m_tx.mutex}; + m_tx.buf.commit(size); + if (size) + m_tx.waiting.wake(); +} + +size_t +channel::get_block(uint8_t const **area, bool block) const +{ + j6::scoped_lock lock {m_rx.mutex}; + while (!m_rx.buf.size()) { + if (!block) return 0; lock.release(); - m_header->read_waiting.wait(); + m_rx.waiting.wait(); lock.acquire(); } - size_t avail = m_header->read_avail(); - size_t read = *size > avail ? avail : *size; + return m_rx.buf.get_block(area); +} - memcpy(buffer, m_header->read_at(), read); - m_header->consume(read); - m_header->write_waiting.wake(); - - *size = read; - return j6_status_ok; +void +channel::consume(size_t size) +{ + j6::syslog(logs::ipc, log_level::spam, + "Read %d bytes from channel on {%x}", size, m_def.rx); + m_rx.buf.consume(size); + if (size) + m_rx.waiting.wake(); } } // namespace j6 diff --git a/src/libraries/j6/include/j6/channel.hh b/src/libraries/j6/include/j6/channel.hh index 9a434fe..7f0974e 100644 --- a/src/libraries/j6/include/j6/channel.hh +++ b/src/libraries/j6/include/j6/channel.hh @@ -10,41 +10,66 @@ #include #include +namespace util { + class bip_buffer; +} + namespace j6 { +/// Descriptor of VMAs for a channel. +struct channel_def +{ + j6_handle_t tx; + j6_handle_t rx; +}; + +struct channel_memory_area; + class API channel { public: - /// Create a new channel of the given size. - static channel * create(size_t size); + /// Create a new channel. + /// \arg tx_size Size of the transmit buffer (sending from this thread) + /// \arg rx_size Size of the receive buffer (sending from remote thread), + /// or 0 for equal sized buffers. + static channel * create(size_t tx_size, size_t rx_size = 0); - /// Open an existing channel for which we have a VMA handle - static channel * open(j6_handle_t vma); + /// Open an existing channel for which we have VMA handles + static channel * open(const channel_def &def); - /// Send data into the channel. - /// \arg buffer The buffer from which to read data - /// \arg len The number of bytes to read from `buffer` - /// \arg block If true, block this thread if there aren't `len` bytes of space available - j6_status_t send(const void *buffer, size_t len, bool block = true); + /// Reserve an area of the output buffer for a write. + /// \arg size Requested size, in bytes + /// \arg area [out] Pointer to returned area + /// \arg block If true, block this thread until there are size bytes free + /// \returns Size of returned area, in bytes, or 0 on failure + size_t reserve(size_t size, uint8_t **area, bool block = true); - /// Read data out of the channel. - /// \arg buffer The buffer to receive channel data - /// \arg size [in] The size of `buffer` [out] the amount read into `buffer` - /// \arg block If true, block this thread if there is no data to read yet - j6_status_t receive(void *buffer, size_t *size, bool block = true); + /// Commit a pending write started by reserve() + /// \arg size Amount of data used, in bytes + void commit(size_t size); - /// Get the VMA handle for sharing with other processes - j6_handle_t handle() const { return m_vma; } + /// Get a pointer to a block of data in the buffer. + /// \arg area [out] Pointer to the retuned area + /// \arg block If true, block this thread until there is data available + /// \returns Size of the returned area, in bytes + size_t get_block(uint8_t const **area, bool block = true) const; + + /// Mark a number of bytes as consumed, freeing buffer space + /// \arg size Number of bytes to consume + void consume(size_t size); + + /// Get the channel_def for creating the remote end + inline channel_def remote_def() const { return {m_def.rx, m_def.tx}; } private: - struct header; + channel( + const channel_def &def, + channel_memory_area &tx, + channel_memory_area &rx); - channel(j6_handle_t vma, header *h); - - j6_handle_t m_vma; - - size_t m_size; - header *m_header; + channel_def m_def; + channel_memory_area &m_tx; + channel_memory_area &m_rx; }; } // namespace j6 diff --git a/src/libraries/j6/include/j6/protocols/service_locator.hh b/src/libraries/j6/include/j6/protocols/service_locator.hh index 57be069..ebdd01e 100644 --- a/src/libraries/j6/include/j6/protocols/service_locator.hh +++ b/src/libraries/j6/include/j6/protocols/service_locator.hh @@ -1,6 +1,7 @@ #include #include #include +#include namespace j6::proto::sl { @@ -13,16 +14,16 @@ public: /// Register a handle as a service with the locator. /// \arg proto_id The protocol this handle supports - /// \arg handle The mailbox or channel handle - j6_status_t register_service(uint64_t proto_id, j6_handle_t handle); + /// \arg handles The mailbox or channel handles + j6_status_t register_service(uint64_t proto_id, util::counted handles); /// Look up a handle with the locator service. /// \arg proto_id The protocol to look for - /// \arg handle [out] The mailbox or channel handle - j6_status_t lookup_service(uint64_t proto_id, j6_handle_t &handle); + /// \arg handles [out] The mailbox or channel handles + j6_status_t lookup_service(uint64_t proto_id, util::counted &handles); private: j6_handle_t m_service; }; -} // namespace j6::proto::sl \ No newline at end of file +} // namespace j6::proto::sl diff --git a/src/libraries/j6/include/j6/tables/log_areas.inc b/src/libraries/j6/include/j6/tables/log_areas.inc index ae83c06..83f7ed8 100644 --- a/src/libraries/j6/include/j6/tables/log_areas.inc +++ b/src/libraries/j6/include/j6/tables/log_areas.inc @@ -1,15 +1,15 @@ LOG(apic, info) LOG(boot, info) -LOG(device, spam) +LOG(device, info) LOG(irq, info) -LOG(memory, verbose) -LOG(objs, spam) +LOG(memory, info) +LOG(objs, info) LOG(paging, info) -LOG(sched, verbose) -LOG(syscall,verbose) +LOG(sched, info) +LOG(syscall,info) LOG(task, verbose) LOG(timer, info) LOG(ipc, spam) LOG(app, spam) -LOG(proto, spam) -LOG(srv, spam) +LOG(proto, spam) +LOG(srv, info) diff --git a/src/libraries/j6/protocols/service_locator.cpp b/src/libraries/j6/protocols/service_locator.cpp index e4a5cf2..68a9ab9 100644 --- a/src/libraries/j6/protocols/service_locator.cpp +++ b/src/libraries/j6/protocols/service_locator.cpp @@ -13,16 +13,15 @@ client::client(j6_handle_t slp_mb) : } j6_status_t -client::register_service(uint64_t proto_id, j6_handle_t handle) +client::register_service(uint64_t proto_id, util::counted handles) { uint64_t tag = j6_proto_sl_register; - size_t handle_count = 1; size_t data = proto_id; size_t data_size = sizeof(proto_id); j6_status_t s = j6_mailbox_call(m_service, &tag, &data, &data_size, data_size, - &handle, &handle_count); + handles.pointer, &handles.count, handles.count); if (s != j6_status_ok) return s; @@ -34,31 +33,35 @@ client::register_service(uint64_t proto_id, j6_handle_t handle) } j6_status_t -client::lookup_service(uint64_t proto_id, j6_handle_t &handle) +client::lookup_service(uint64_t proto_id, util::counted &handles) { uint64_t tag = j6_proto_sl_find; - size_t handle_count = 1; size_t data = proto_id; size_t data_size = sizeof(proto_id); - handle = j6_handle_invalid; + size_t handles_size = handles.count; + handles.count = 0; j6::syslog(j6::logs::proto, j6::log_level::verbose, "Looking up service for %x", proto_id); j6_status_t s = j6_mailbox_call(m_service, &tag, &data, &data_size, data_size, - &handle, &handle_count); + handles.pointer, &handles.count, handles_size); - if (s != j6_status_ok) + if (s != j6_status_ok) { + j6::syslog(j6::logs::proto, j6::log_level::error, "Received error %lx trying to call service lookup", s); return s; + } if (tag == j6_proto_sl_result) - return j6_status_ok; // handle is already in `handle` + return j6_status_ok; // handles are already in `handles` - else if (tag == j6_proto_base_status) + else if (tag == j6_proto_base_status) { + j6::syslog(j6::logs::proto, j6::log_level::warn, "Received status %lx from service lookup", data); return data; // contains a status + } return j6_err_unexpected; } } // namespace j6::proto::sl -#endif // __j6kernel \ No newline at end of file +#endif // __j6kernel diff --git a/src/libraries/j6/protocols/vfs.cpp b/src/libraries/j6/protocols/vfs.cpp index fd87a3c..3476df2 100644 --- a/src/libraries/j6/protocols/vfs.cpp +++ b/src/libraries/j6/protocols/vfs.cpp @@ -21,7 +21,7 @@ client::load_file(char *path, j6_handle_t &vma, size_t &size) return j6_err_invalid_arg; uint64_t tag = j6_proto_vfs_load; - size_t handle_count = 1; + size_t handle_count = 0; vma = j6_handle_invalid; // Always need to send a big enough buffer for a status code @@ -38,12 +38,12 @@ client::load_file(char *path, j6_handle_t &vma, size_t &size) j6_status_t s = j6_mailbox_call(m_service, &tag, data, &data_len, path_len, - &vma, &handle_count); + &vma, &handle_count, 1); if (s != j6_status_ok) return s; - if (tag == j6_proto_vfs_file) { + if (tag == j6_proto_vfs_file && handle_count == 1) { size = 0; // Get the size into `size` diff --git a/src/libraries/util/bip_buffer.cpp b/src/libraries/util/bip_buffer.cpp index 548b8f8..799f160 100644 --- a/src/libraries/util/bip_buffer.cpp +++ b/src/libraries/util/bip_buffer.cpp @@ -8,27 +8,37 @@ namespace util { -bip_buffer::bip_buffer() : - m_start_a(0), - m_start_b(0), - m_size_a(0), - m_size_b(0), - m_size_r(0), - m_buffer_size(0), - m_buffer(nullptr) - {} +bip_buffer::bip_buffer(size_t size) : + m_start_a {0}, + m_start_b {0}, + m_size_a {0}, + m_size_b {0}, + m_size_r {0}, + m_buffer_size {size - sizeof(bip_buffer)} +{} -bip_buffer::bip_buffer(uint8_t *buffer, size_t size) : - m_start_a(0), - m_start_b(0), - m_size_a(0), - m_size_b(0), - m_size_r(0), - m_buffer_size(size), - m_buffer(buffer) - {} +size_t +bip_buffer::write_available() const +{ + scoped_lock lock {m_lock}; -size_t bip_buffer::reserve(size_t size, void **area) + if (m_size_r) { + return 0; + } + + if (m_size_b) { + // If B exists, we're appending there. Get space between + // the end of B and start of A. + return m_start_a - m_start_b - m_size_b; + } else { + // B doesn't exist, check the space both before and after A. + size_t remaining = m_buffer_size - m_start_a - m_size_a; + return (m_start_a > remaining) ? m_start_a : remaining; + } +} + +size_t +bip_buffer::reserve(size_t size, uint8_t **area) { scoped_lock lock {m_lock}; @@ -84,7 +94,7 @@ void bip_buffer::commit(size_t size) m_start_r = m_size_r = 0; } -size_t bip_buffer::get_block(void **area) const +size_t bip_buffer::get_block(uint8_t const **area) const { scoped_lock lock {m_lock}; diff --git a/src/libraries/util/include/util/bip_buffer.h b/src/libraries/util/include/util/bip_buffer.h index dd23105..c17885e 100644 --- a/src/libraries/util/include/util/bip_buffer.h +++ b/src/libraries/util/include/util/bip_buffer.h @@ -14,17 +14,14 @@ namespace util { class API bip_buffer { public: - /// Default constructor. Creates a zero-size buffer. - bip_buffer(); - /// Constructor. - bip_buffer(uint8_t *buffer, size_t size); + bip_buffer(size_t size); /// Reserve an area of buffer for a write. /// \arg size Requested size, in bytes /// \arg area [out] Pointer to returned area /// \returns Size of returned area, in bytes, or 0 on failure - size_t reserve(size_t size, void **area); + size_t reserve(size_t size, uint8_t **area); /// Commit a pending write started by reserve() /// \arg size Amount of data used, in bytes @@ -33,7 +30,7 @@ public: /// Get a pointer to a block of data in the buffer. /// \arg area [out] Pointer to the retuned area /// \returns Size of the returned area, in bytes - size_t get_block(void **area) const; + size_t get_block(uint8_t const **area) const; /// Mark a number of bytes as consumed, freeing buffer space /// \arg size Number of bytes to consume @@ -47,6 +44,13 @@ public: /// \returns Number of bytes of buffer that are free inline size_t free_space() const { return m_buffer_size - size(); } + /// Get total size of the buffer + /// \returns Number of bytes in the buffer + inline size_t buffer_size() const { return m_buffer_size; } + + /// Get the current size available for a contiguous write + size_t write_available() const; + private: size_t m_start_a; size_t m_start_b; @@ -56,9 +60,10 @@ private: size_t m_size_r; mutable spinlock m_lock; - const size_t m_buffer_size; - uint8_t * const m_buffer; + uint8_t m_buffer[0]; + + bip_buffer() = delete; }; } // namespace util diff --git a/src/libraries/util/include/util/pointers.h b/src/libraries/util/include/util/pointers.h index 99d3d00..abf6432 100644 --- a/src/libraries/util/include/util/pointers.h +++ b/src/libraries/util/include/util/pointers.h @@ -4,6 +4,7 @@ #include #include +#include namespace util { @@ -92,4 +93,45 @@ private: size_t m_off; }; + +template +class unique_ptr +{ +public: + unique_ptr() : m_value {nullptr} {} + unique_ptr(T *p) : m_value {p} {} + unique_ptr(unique_ptr &&o) { *this = util::move(o); } + + ~unique_ptr() { delete m_value; } + + unique_ptr & operator=(unique_ptr &&o) { + if (o.m_value == m_value) return *this; + delete m_value; + + m_value = o.m_value; + o.m_value = nullptr; + return *this; + } + + unique_ptr(const unique_ptr &) = delete; + unique_ptr & operator=(const unique_ptr &) = delete; + + T* get() { return m_value; } + const T* get() const { return m_value; } + operator bool() const { return m_value; } + bool empty() const { return m_value = nullptr; } + + T* operator->() { return m_value; } + const T operator->() const { return m_value; } + + T operator*() { return *m_value; } + const T operator*() const { return *m_value; } + + operator T*() { return m_value; } + operator const T*() const { return m_value; } + +private: + T *m_value = nullptr; +}; + } // namespace util diff --git a/src/user/6s/6s.module b/src/user/6s/6s.module new file mode 100644 index 0000000..010a01b --- /dev/null +++ b/src/user/6s/6s.module @@ -0,0 +1,9 @@ +# vim: ft=python + +module("6s", + targets = [ "user" ], + deps = [ "libc" ], + description = "j6 shell", + sources = [ + "main.cpp", + ]) diff --git a/src/user/6s/main.cpp b/src/user/6s/main.cpp new file mode 100644 index 0000000..ac1dbd6 --- /dev/null +++ b/src/user/6s/main.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + int main(int, const char **); +} + +j6_handle_t g_handle_sys = j6_handle_invalid; + +const char prompt[] = "\r\nj6> "; +static constexpr size_t prompt_len = sizeof(prompt) - 1; + +size_t +gather_command(j6::channel &cout, j6::ring_buffer &buf) +{ + size_t total_len = buf.used(); + + while (true) { + size_t size = buf.free(); + char *start = buf.write_ptr(); + + uint8_t const *input = nullptr; + size_t n = cout.get_block(&input); + if (n > size) n = size; + + uint8_t *outp = nullptr; + cout.reserve(n, &outp, true); + + size_t i = 0; + bool newline = false; + while (i < n) { + start[i] = input[i]; + outp[i] = input[i]; + j6::syslog(j6::logs::app, j6::log_level::spam, "Read: %x", start[i]); + if (start[i++] == '\r') { + newline = true; + break; + } + } + + size_t written = i; + if (newline) + outp[written++] = '\n'; + cout.commit(written); + cout.consume(i); + + if (newline) + return total_len + i; + + total_len += size; + } +} + +int +main(int argc, const char **argv) +{ + j6_handle_t event = j6_handle_invalid; + j6_status_t result = j6_status_ok; + + g_handle_sys = j6_find_init_handle(0); + if (g_handle_sys == j6_handle_invalid) + return 1; + + static constexpr size_t buffer_pages = 1; + j6::ring_buffer in_buffer {buffer_pages}; + if (!in_buffer.valid()) + return 2; + + j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id); + if (slp == j6_handle_invalid) + return 3; + + uint64_t proto_id = "jsix.protocol.stream.ouput"_id; + j6::proto::sl::client slp_client {slp}; + + j6_handle_t chan_handles[2]; + util::counted handles {chan_handles, 2}; + + for (unsigned i = 0; i < 100; ++i) { + j6_status_t s = slp_client.lookup_service(proto_id, handles); + if (s == j6_status_ok && handles.count) + break; + + j6_thread_sleep(10000); // 10ms + } + + if (!handles.count) + return 4; + + j6::channel *cout = j6::channel::open({chan_handles[0], chan_handles[1]}); + if (!cout) + return 5; + + while (true) { + uint8_t *outp = nullptr; + cout->reserve(prompt_len, &outp, true); + for (size_t i = 0; i < prompt_len; ++i) + outp[i] = prompt[i]; + cout->commit(prompt_len); + + const char *inp = in_buffer.read_ptr(); + size_t size = gather_command(*cout, in_buffer); + in_buffer.consume(size); + } +} diff --git a/src/user/drv.uart/main.cpp b/src/user/drv.uart/main.cpp index b6987a5..0f8289b 100644 --- a/src/user/drv.uart/main.cpp +++ b/src/user/drv.uart/main.cpp @@ -51,6 +51,32 @@ main(int argc, const char **argv) if (result != j6_status_ok) return result; + static constexpr size_t buffer_pages = 1; + j6::ring_buffer in_buffer {buffer_pages}; + if (!in_buffer.valid()) + return 128; + + j6::ring_buffer out_buffer {buffer_pages}; + if (!out_buffer.valid()) + return 129; + + j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id); + if (slp == j6_handle_invalid) + return 1; + + j6::channel *cout = j6::channel::create(0x2000); + if (!cout) + return 2; + + uint64_t proto_id = "jsix.protocol.stream.ouput"_id; + j6::channel_def chan = cout->remote_def(); + j6::proto::sl::client slp_client {slp}; + + j6_handle_t chan_handles[2] = {chan.tx, chan.rx}; + result = slp_client.register_service(proto_id, {chan_handles, 2}); + if (result != j6_status_ok) + return 4; + result = j6_event_create(&event); if (result != j6_status_ok) return result; @@ -63,46 +89,15 @@ main(int argc, const char **argv) if (result != j6_status_ok) return result; - serial_port com1 {COM1, in_buf_size, com1_in, out_buf_size, com1_out}; - serial_port com2 {COM2, in_buf_size, com2_in, out_buf_size, com2_out}; - - static constexpr size_t buffer_pages = 1; - j6::ring_buffer buffer {buffer_pages}; - if (!buffer.valid()) - return 128; - - j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id); - if (slp == j6_handle_invalid) - return 1; - - j6::channel *cout = j6::channel::create(0x2000); - if (!cout) - return 2; - - uint64_t proto_id = "jsix.protocol.stream.ouput"_id; - uint64_t handle = cout->handle(); - j6::proto::sl::client slp_client {slp}; - result = slp_client.register_service(proto_id, handle); - if (result != j6_status_ok) - return 4; - - result = j6_system_request_iopl(g_handle_sys, 3); - if (result != j6_status_ok) - return 6; + serial_port com1 {COM1, *cout}; + //serial_port com2 {COM2, *cout}; while (true) { - size_t size = buffer.free(); - cout->receive(buffer.write_ptr(), &size, 0); - buffer.commit(size); - //j6::syslog(j6::logs::srv, j6::log_level::spam, "uart driver: got %d bytes from channel", size); - - size = com1.write(buffer.read_ptr(), buffer.used()); - buffer.consume(size); - uint64_t signals = 0; result = j6_event_wait(event, &signals, 500); if (result == j6_err_timed_out) { - com1.do_write(); + com1.handle_interrupt(); + //com2.handle_interrupt(); continue; } @@ -114,11 +109,11 @@ main(int argc, const char **argv) } if (signals & (1<<0)) - com2.handle_interrupt(); + //com2.handle_interrupt(); if (signals & (1<<1)) com1.handle_interrupt(); } j6::syslog(j6::logs::srv, j6::log_level::error, "uart driver somehow got to the end of main"); return 0; -} \ No newline at end of file +} diff --git a/src/user/drv.uart/serial.cpp b/src/user/drv.uart/serial.cpp index a6150bb..1eda833 100644 --- a/src/user/drv.uart/serial.cpp +++ b/src/user/drv.uart/serial.cpp @@ -1,4 +1,6 @@ +#include #include +#include #include "io.h" #include "serial.h" @@ -18,13 +20,10 @@ constexpr uint16_t MSR = 6; constexpr uint16_t DLL = 0; // DLAB == 1 constexpr uint16_t DLH = 1; // DLAB == 1 -serial_port::serial_port(uint16_t port, - size_t in_buffer_len, uint8_t *in_buffer, - size_t out_buffer_len, uint8_t *out_buffer) : - m_writing(false), - m_port(port), - m_out_buffer(out_buffer, out_buffer_len), - m_in_buffer(in_buffer, in_buffer_len) +serial_port::serial_port(uint16_t port, j6::channel &channel) : + m_writing {false}, + m_port {port}, + m_chan {channel} { outb(port + IER, 0x00); // Disable all interrupts outb(port + LCR, 0x80); // Enable the Divisor Latch Access Bit @@ -56,10 +55,8 @@ serial_port::handle_interrupt() break; case 1: // Transmit buffer empty - do_write(); - break; - case 2: // Received data available + do_write(); do_read(); break; @@ -78,14 +75,15 @@ serial_port::do_read() { size_t used = 0; uint8_t *data = nullptr; - size_t avail = m_in_buffer.reserve(fifo_size, reinterpret_cast(&data)); + + size_t avail = m_chan.reserve(fifo_size, &data, false); while (used < avail && read_ready(m_port)) { *data++ = inb(m_port); used++; } - m_in_buffer.commit(used); + m_chan.commit(used); } void @@ -93,12 +91,12 @@ serial_port::do_write() { util::scoped_lock lock {m_lock}; - uint8_t *data = nullptr; - size_t n = m_out_buffer.get_block(reinterpret_cast(&data)); + uint8_t const *data = nullptr; + size_t n = m_chan.get_block(&data, false); m_writing = (n > 0); if (!m_writing) { - m_out_buffer.consume(0); + m_chan.consume(0); return; } @@ -113,7 +111,7 @@ serial_port::do_write() outb(m_port, data[i]); } - m_out_buffer.consume(n); + m_chan.consume(n); } void @@ -125,11 +123,11 @@ serial_port::handle_error(uint16_t reg, uint8_t value) char serial_port::read() { - uint8_t *data = nullptr; - size_t n = m_in_buffer.get_block(reinterpret_cast(&data)); + uint8_t const *data = nullptr; + size_t n = m_chan.get_block(&data); if (!n) return 0; char c = *data; - m_in_buffer.consume(1); + m_chan.consume(1); return c; } @@ -137,10 +135,10 @@ size_t serial_port::write(const char *c, size_t len) { uint8_t *data = nullptr; - size_t avail = m_out_buffer.reserve(len, reinterpret_cast(&data)); + size_t avail = m_chan.reserve(len, &data); memcpy(data, c, avail); - m_out_buffer.commit(avail); + m_chan.commit(avail); if (!m_writing) do_write(); diff --git a/src/user/drv.uart/serial.h b/src/user/drv.uart/serial.h index a67b239..940e7fb 100644 --- a/src/user/drv.uart/serial.h +++ b/src/user/drv.uart/serial.h @@ -6,14 +6,17 @@ #include #include +namespace j6 { + class channel; +} + class serial_port { public: /// Constructor. - /// \arg port The IO address of the serial port - serial_port(uint16_t port, - size_t in_buffer_len, uint8_t *in_buffer, - size_t out_buffer_len, uint8_t *out_buffer); + /// \arg port The IO address of the serial port + /// \art channel The channel to send bytes over + serial_port(uint16_t port, j6::channel &channel); size_t write(const char *str, size_t len); char read(); @@ -24,8 +27,7 @@ public: private: bool m_writing; uint16_t m_port; - util::bip_buffer m_out_buffer; - util::bip_buffer m_in_buffer; + j6::channel &m_chan; util::spinlock m_lock; void do_read(); diff --git a/src/user/ld.so/image.cpp b/src/user/ld.so/image.cpp index 829f072..ca29a9b 100644 --- a/src/user/ld.so/image.cpp +++ b/src/user/ld.so/image.cpp @@ -283,7 +283,7 @@ image_list::load(j6_handle_t vfs_mb, uintptr_t addr) return; } - j6::syslog(j6::logs::app, j6::log_level::verbose, "Loaded %s at base address 0x%x", img->name, img->base); + j6::syslog(j6::logs::app, j6::log_level::verbose, "Loaded %s at offset 0x%lx", img->name, img->base); addr = (addr & ~0xffffull) + 0x10000; // Find the DT_NEEDED entries diff --git a/src/user/ld.so/main.cpp b/src/user/ld.so/main.cpp index 63a839d..78d7d89 100644 --- a/src/user/ld.so/main.cpp +++ b/src/user/ld.so/main.cpp @@ -72,5 +72,6 @@ ldso_init(j6_arg_header *stack_args, uintptr_t *got) all_images.push_back(&target_image); all_images.load(vfs, arg_loader->start_addr); + j6::syslog(j6::logs::app, j6::log_level::verbose, "ld.so finished, jumping to entrypoint"); return arg_loader->entrypoint + arg_loader->image_base; } diff --git a/src/user/srv.init/initfs.cpp b/src/user/srv.init/initfs.cpp index f5bf3e0..19ce08c 100644 --- a/src/user/srv.init/initfs.cpp +++ b/src/user/srv.init/initfs.cpp @@ -32,9 +32,13 @@ handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma) void sanitize(char *s, size_t len) { - if (len >= buffer_size) len--; + if (!s) return; + if (len >= buffer_size) + len = buffer_size - 1; + for (size_t i = 0; i < len; ++i) - if (!s || !*s) return; + if (!s[i]) return; + s[len] = 0; } @@ -44,17 +48,18 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb) uint64_t tag = 0; char *buffer = new char [buffer_size]; - size_t out_len = buffer_size; + size_t out_len = 0; uint64_t reply_tag = 0; - size_t handles_count = 1; + static constexpr size_t max_handles = 1; + size_t handles_count = 0; j6_handle_t give_handle = j6_handle_invalid; uint64_t proto_id; j6_status_t s = j6_mailbox_respond(mb, &tag, - buffer, &out_len, 0, - &give_handle, &handles_count, + buffer, &out_len, buffer_size, + &give_handle, &handles_count, max_handles, &reply_tag, j6_flag_block); while (initfs_running) { @@ -63,8 +68,6 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb) return; } - size_t data_out = 0; - switch (tag) { case j6_proto_vfs_load: sanitize(buffer, out_len); @@ -72,23 +75,25 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb) if (s != j6_status_ok) { tag = j6_proto_base_status; *reinterpret_cast(buffer) = s; - data_out = sizeof(j6_status_t); + out_len = sizeof(j6_status_t); break; } + handles_count = 1; tag = j6_proto_vfs_file; break; default: tag = j6_proto_base_status; *reinterpret_cast(buffer) = j6_err_invalid_arg; - data_out = sizeof(j6_status_t); + out_len = sizeof(j6_status_t); give_handle = j6_handle_invalid; + handles_count = 0; } out_len = buffer_size; s = j6_mailbox_respond(mb, &tag, - buffer, &out_len, data_out, - &give_handle, &handles_count, + buffer, &out_len, buffer_size, + &give_handle, &handles_count, max_handles, &reply_tag, j6_flag_block); } } diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index febd3b7..bdccfe6 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -12,6 +12,7 @@ #include #include +#include "j6/types.h" #include "j6romfs.h" #include "loader.h" @@ -192,6 +193,10 @@ load_program( const module *arg) { j6::syslog(j6::logs::srv, j6::log_level::info, "Loading program '%s' into new process", path); + j6_handle_t proc = create_process(sys, slp, vfs); + if (proc == j6_handle_invalid) + return false; + util::buffer program_data = load_file(fs, path); if (!program_data.pointer) return false; @@ -200,15 +205,16 @@ load_program( bool dyn = program_elf.type() == elf::filetype::shared; uintptr_t program_image_base = 0; - if (dyn) + if (dyn) { program_image_base = (rng.next() & 0xffe0 + 16) << 20; + j6::syslog(j6::logs::srv, j6::log_level::info, " Image %s offset: 0x%lx", path, program_image_base); + } if (!program_elf.valid(dyn ? elf::filetype::shared : elf::filetype::executable)) { j6::syslog(j6::logs::srv, j6::log_level::error, "error loading '%s': ELF is invalid", path); return false; } - j6_handle_t proc = create_process(sys, slp, vfs); uintptr_t eop = load_program_into(proc, program_elf, program_image_base, path); if (!eop) return false; @@ -273,6 +279,7 @@ load_program( if (seg.type == elf::segment_type::interpreter) { const char *ldso_path = reinterpret_cast(program_elf.base() + seg.offset); util::buffer ldso_data = load_file(fs, ldso_path); + j6::syslog(j6::logs::srv, j6::log_level::info, " Image %s offset: 0x%lx", ldso_path, ldso_image_base); if (!ldso_data.pointer) return false; diff --git a/src/user/srv.init/service_locator.cpp b/src/user/srv.init/service_locator.cpp index a1a27a9..4cb646e 100644 --- a/src/user/srv.init/service_locator.cpp +++ b/src/user/srv.init/service_locator.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "service_locator.h" @@ -14,7 +15,7 @@ struct handle_entry { uint64_t protocol; - j6_handle_t handle; + util::counted handles; }; uint64_t & get_map_key(handle_entry &e) { return e.protocol; } @@ -23,14 +24,16 @@ void service_locator_start(j6_handle_t mb) { // TODO: This should be a multimap - std::unordered_map services; + util::node_map services; uint64_t tag = 0; uint64_t data = 0; - uint64_t handle_count = 1; uint64_t reply_tag = 0; - j6_handle_t give_handle = j6_handle_invalid; + static constexpr size_t max_handles = 16; + uint64_t handle_count = 0; + j6_handle_t give_handles[max_handles]; + j6_handle_t *save_handles = nullptr; uint64_t proto_id; j6::syslog(j6::logs::proto, j6::log_level::verbose, "SL> Starting service locator on mbx handle %x", mb); @@ -39,29 +42,32 @@ service_locator_start(j6_handle_t mb) uint64_t data_len = sizeof(uint64_t); j6_status_t s = j6_mailbox_respond(mb, &tag, &data, &data_len, data_len, - &give_handle, &handle_count, + give_handles, &handle_count, max_handles, &reply_tag, j6_flag_block); - if (s != j6_status_ok) - exit(128); - - handle_entry *found = nullptr; + if (s != j6_status_ok) { + j6::syslog(j6::logs::proto, j6::log_level::error, "SL> Syscall returned error %lx, dying", s); + continue; + } switch (tag) { case j6_proto_sl_register: proto_id = data; - if (give_handle == j6_handle_invalid) { + if (!handle_count) { tag = j6_proto_base_status; data = j6_err_invalid_arg; break; } - j6::syslog(j6::logs::proto, j6::log_level::verbose, "SL> Registering handle %x for proto %x", give_handle, proto_id); + j6::syslog(j6::logs::proto, j6::log_level::verbose, "SL> Registering %d handles for proto %x", handle_count, proto_id); - services.insert( {proto_id, give_handle} ); + save_handles = new j6_handle_t [handle_count]; + memcpy(save_handles, give_handles, sizeof(j6_handle_t) * handle_count); + services.insert( {proto_id, {save_handles, handle_count}} ); tag = j6_proto_base_status; data = j6_status_ok; - give_handle = j6_handle_invalid; + save_handles = nullptr; + handle_count = 0; break; case j6_proto_sl_find: @@ -70,13 +76,14 @@ service_locator_start(j6_handle_t mb) data = 0; { - auto found = services.find(proto_id); - if (found != services.end()) { - j6::syslog(j6::logs::proto, j6::log_level::verbose, "SL> Found handle %x for proto %x", give_handle, proto_id); - give_handle = found->second; + handle_entry *found = services.find(proto_id); + if (found) { + handle_count = found->handles.count; + memcpy(give_handles, found->handles.pointer, sizeof(j6_handle_t) * handle_count); + j6::syslog(j6::logs::proto, j6::log_level::verbose, "SL> Found %d handles for proto %x", handle_count, proto_id); } else { + handle_count = 0; j6::syslog(j6::logs::proto, j6::log_level::verbose, "SL> Found no handles for proto %x", proto_id); - give_handle = j6_handle_invalid; } } break; @@ -84,7 +91,7 @@ service_locator_start(j6_handle_t mb) default: tag = j6_proto_base_status; data = j6_err_invalid_arg; - give_handle = j6_handle_invalid; + handle_count = 0; break; } }