summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/serial.c
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2024-03-11 21:30:31 -0400
committerJon Santmyer <jon@jonsantmyer.com>2024-03-11 21:30:31 -0400
commitd1ff7bcc91886626dc9060ec5fb67ee102ab7c1d (patch)
tree8f0b5cd8aad31089131785dc6e37b659490f9955 /arch/x86_64/serial.c
downloadjove-kernel-d1ff7bcc91886626dc9060ec5fb67ee102ab7c1d.tar.gz
jove-kernel-d1ff7bcc91886626dc9060ec5fb67ee102ab7c1d.tar.bz2
jove-kernel-d1ff7bcc91886626dc9060ec5fb67ee102ab7c1d.zip
usermode capable kernel with logging syscall
Diffstat (limited to 'arch/x86_64/serial.c')
-rw-r--r--arch/x86_64/serial.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/arch/x86_64/serial.c b/arch/x86_64/serial.c
new file mode 100644
index 0000000..1b49e3f
--- /dev/null
+++ b/arch/x86_64/serial.c
@@ -0,0 +1,62 @@
+#include "serial.h"
+#include "uart.h"
+#include "io/log.h"
+
+static struct LogDevice s_serial_logdev =
+ { .out = serial_out, .chain = NULL };
+
+bool serial_supported = true;
+
+void
+serial_setup(void)
+{
+ /* Disable interrupts. */
+ poutb(SERIAL_UART_COM_IER(SERIAL_UART_COM1), 0x0);
+ /* Enable DLAB. */
+ poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 0x80);
+ /* Set divisor to 3 (38400 baud)*/
+ poutb(SERIAL_UART_COM_DLAB_DLL(SERIAL_UART_COM1), 3);
+ poutb(SERIAL_UART_COM_DLAB_DLH(SERIAL_UART_COM1), 0);
+ /* Set flags for LCR (8 bits, no parity, one stop)*/
+ poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 1 | 2);
+ /* Enable & clear FIFO, 14-byte threshold */
+ poutb(SERIAL_UART_COM_FCR(SERIAL_UART_COM1), 1 | 2 | 4 | 0xC0);
+ /* Enable interrupts, set RTS/DSR. */
+ poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 8);
+ /* Set loopback mode for testing. */
+ poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 2 | 4 | 8 | 0x10);
+ /* Test serial output. */
+ poutb(SERIAL_UART_COM1, 0xAE);
+ if(pinb(SERIAL_UART_COM1) != 0xAE) {
+ serial_supported = false;
+ return;
+ }
+
+ /* Serial is not faulty.
+ * No loopback, enable output 1 & 2.*/
+ poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 4 | 8);
+
+ klog_newdev(&s_serial_logdev);
+}
+
+static ALWAYS_INLINE bool
+serial_transmit_empty(uint16_t com)
+{
+ return pinb(SERIAL_UART_COM_LSR(com) & 0x20);
+}
+
+static inline void
+serial_outb(uint16_t com, uint8_t b)
+{
+ if(b == '\n') serial_outb(com, '\r');
+ while(!serial_transmit_empty(SERIAL_UART_COM1));
+ poutb(com, b);
+}
+
+void
+serial_out(const char *s, size_t len)
+{
+ if(!serial_supported) return;
+ for(; len > 0; len--)
+ serial_outb(SERIAL_UART_COM1, *(s++));
+}