[6s] Add 6s shell, make channels full-duplex

This commit adds the 6s shell, and a bunch of supporting work for it.
Major changes include:

- New shell.yaml manifest to give 6s control of the TTY instead of
  srv.logger
- Changes to mailbox syscalls to add max handles array size separate
  from input size. Also reversed the meaning of the similar data size
  argument in those syscalls. (Using the second arg as the max array
  size and the first as the current valid size allows for the auto
  verify code to verify handles properly, and simplifies user-side
  code.)
- New util::unique_ptr smart pointer class similar to std::unique_ptr
- New ipc::message format that uses util::unique_ptr to manage ownership
  and lifetimes and avoid extra copying.
- The service locator protocol now supports multiple handles per entry
- Channels got a major overhaul. They are now split into two VMAs, each
  containing a mutex, a condition, and a util::bip_buffer. The order of
  the VMAs determines which end of the pipe you're on. (ie, the creator
  swaps them before handing them to the other thread.) Their API also
  changed to be similar to that of util::bip_buffer, to avoid extra
  copies.
- util::bip_buffer now keeps its state and its buffer together, so that
  there are no pointers. This allows multiple processes to share them in
  shared memory, like in channels.
- The UART driver changed from keeping buffers for the serial ports to
  just keeping a channel, and the serial port objects read/write
  directly from/to the channel.

Known issues:

- The shell doesn't actually do anything yet. It echos its input back to
  the serial line and injects a prompt on new lines.
- The shell is one character behind in printing back to the serial line.
This commit is contained in:
Justin C. Miller
2024-04-23 23:32:28 -07:00
parent d8a21608c3
commit e725795a17
30 changed files with 727 additions and 323 deletions

111
src/user/6s/main.cpp Normal file
View File

@@ -0,0 +1,111 @@
#include <j6/channel.hh>
#include <j6/init.h>
#include <j6/errors.h>
#include <j6/protocols/service_locator.hh>
#include <j6/ring_buffer.hh>
#include <j6/syscalls.h>
#include <j6/syslog.hh>
#include <j6/types.h>
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<j6_handle_t> 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);
}
}