From eed3b390e3e74440d07a7f62d2e384269a05dd24 Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 4 May 2023 22:48:09 -0300 Subject: [PATCH] kernel: console --- kernel-src/arch/x86-64/main.c | 4 + kernel-src/include/kernel/console.h | 10 ++ kernel-src/include/kernel/devfs.h | 1 + kernel-src/include/termios.h | 30 +++++ kernel-src/io/console.c | 177 ++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+) create mode 100644 kernel-src/include/kernel/console.h create mode 100644 kernel-src/include/termios.h create mode 100644 kernel-src/io/console.c diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index 5ddd9876..800b800b 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -21,6 +21,7 @@ #include #include #include +#include static cpu_t bsp_cpu; @@ -62,5 +63,8 @@ void kernel_entry() { keyboard_init(); arch_ps2_init(); + console_init(); + logging_sethook(console_putc); + __assert(!"kernel entry end"); } diff --git a/kernel-src/include/kernel/console.h b/kernel-src/include/kernel/console.h new file mode 100644 index 00000000..3fb0e3ea --- /dev/null +++ b/kernel-src/include/kernel/console.h @@ -0,0 +1,10 @@ +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +void console_init(); +void console_putc(char c); +void console_write(char *str, size_t size); + +#endif diff --git a/kernel-src/include/kernel/devfs.h b/kernel-src/include/kernel/devfs.h index 364c0a6b..d3de0887 100644 --- a/kernel-src/include/kernel/devfs.h +++ b/kernel-src/include/kernel/devfs.h @@ -6,6 +6,7 @@ #define DEV_MAJOR_NULL 1 #define DEV_MAJOR_FULL 2 #define DEV_MAJOR_ZERO 3 +#define DEV_MAJOR_CONSOLE 4 typedef struct { int (*open)(int minor, int flags); diff --git a/kernel-src/include/termios.h b/kernel-src/include/termios.h new file mode 100644 index 00000000..6131420e --- /dev/null +++ b/kernel-src/include/termios.h @@ -0,0 +1,30 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define VINTR 0 +#define ISIG 0000001 +#define NCCS 32 +#define ECHO 0000010 +#define ICANON 0000002 +#define VMIN 6 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define OCRNL 0000010 + +typedef struct { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +} termios_t; + +#endif diff --git a/kernel-src/io/console.c b/kernel-src/io/console.c new file mode 100644 index 00000000..c957b5f5 --- /dev/null +++ b/kernel-src/io/console.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 4096 +static mutex_t writemutex; +static mutex_t readmutex; +static semaphore_t readsemaphore; +static ringbuffer_t readbuffer; +static thread_t *thread; +static termios_t termios; + +void console_write(char *str, size_t count) { + MUTEX_ACQUIRE(&writemutex, false); + + term_write(str, count); + + MUTEX_RELEASE(&writemutex); +} + +void console_putc(char c) { + console_write(&c, 1); +} + +#define THREAD_BUFFER_SIZE 128 + +static void consolethread() { + char buffer[THREAD_BUFFER_SIZE + 1]; + uintmax_t buffpos = 0; + + for (;;) { + kbpacket_t packet; + keyboard_wait(keyboard_console, &packet); + if (packet.flags & KBPACKET_FLAGS_RELEASED) + continue; + + char asciibuffer[2] = {0, 0}; + char *target = asciibuffer; + + if (packet.ascii) { + if (packet.ascii == '\r' && (termios.c_iflag & IGNCR)) + continue; + + if (packet.ascii == '\r' && (termios.c_iflag & ICRNL)) + packet.ascii = '\n'; + + if (packet.ascii == '\n' && (termios.c_iflag & INLCR)) + packet.ascii = '\r'; + + // TODO TRANSLATE TO CTRL CODE IF APPLICABLE + } else { + // TODO SWITCH OF SPECIAL KEYS + } + + asciibuffer[0] = packet.ascii; + size_t targetlen = strlen(target); + if (targetlen == 0) + continue; + + if (termios.c_lflag & ICANON) { + bool flush = false; + if (packet.ascii == '\b') { + if (buffpos == 0) + continue; + --buffpos; + buffer[buffpos] = '\0'; + if (termios.c_lflag & ECHO) + console_write("\b \b", 3); + continue; + } else if (packet.ascii == '\n') { + flush = true; + } + + if (termios.c_lflag & ECHO) + console_write(target, targetlen); + + for (size_t i = 0; i < targetlen; ++i) { + buffer[buffpos++] = target[i]; + if (buffpos == THREAD_BUFFER_SIZE) { + flush = true; + break; + } + } + + if (flush) { + MUTEX_ACQUIRE(&readmutex, false); + bool hasdata = readbuffer.write - readbuffer.read > 0; + ringbuffer_write(&readbuffer, buffer, buffpos); + buffpos = 0; + if (hasdata == false) + semaphore_signal(&readsemaphore); + MUTEX_RELEASE(&readmutex); + } + } else { + if (termios.c_lflag & ECHO) + console_write(target, targetlen); + + MUTEX_ACQUIRE(&readmutex, false); + bool hasdata = readbuffer.write - readbuffer.read > 0; + ringbuffer_write(&readbuffer, target, targetlen); + if (hasdata == false) + semaphore_signal(&readsemaphore); + MUTEX_RELEASE(&readmutex); + } + } +} + +static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc) { + size_t total = 0; + for (;;) { + if (semaphore_test(&readsemaphore) == false) { + *readc = 0; + if (termios.c_cc[VMIN] == 0) + return 0; + + if (flags & V_FFLAGS_NONBLOCKING) + return EAGAIN; + + int i = semaphore_wait(&readsemaphore, true); + if (i) + return i; + } + + MUTEX_ACQUIRE(&readmutex, false); + + size_t read = ringbuffer_read(&readbuffer, buffer, size); + size_t left = readbuffer.write - readbuffer.read; + + MUTEX_RELEASE(&readmutex); + + size -= read; + buffer = (void *)((uintptr_t)buffer + read); + total += read; + + if (size == 0 || total >= termios.c_cc[VMIN]) { + if (left > 0) + semaphore_signal(&readsemaphore); + *readc = total; + return 0; + } + } +} + +static int write(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec) { + *writec = size; + console_write(buffer, size); + return 0; +} + +static devops_t devops = { + .write = write, + .read = read +}; + +void console_init() { + SEMAPHORE_INIT(&readsemaphore, 0); + MUTEX_INIT(&writemutex); + MUTEX_INIT(&readmutex); + __assert(ringbuffer_init(&readbuffer, BUFFER_SIZE) == 0); + __assert(devfs_register(&devops, "console", V_TYPE_CHDEV, DEV_MAJOR_CONSOLE, 0, 0644) == 0); + thread = sched_newthread(consolethread, PAGE_SIZE * 16, 0, NULL, NULL); + __assert(thread); + sched_queue(thread); + + termios.c_iflag = ICRNL; + termios.c_lflag = ECHO | ICANON | ISIG; + termios.c_cc[VINTR] = 0x03; + termios.ibaud = 38400; + termios.obaud = 38400; + termios.c_cc[VMIN] = 1; +}