From da2bbef4e4f586ecf13cd5ffe9a62df3114a3483 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Apr 2022 21:13:00 +0200 Subject: kernel: add a /com1 device --- src/kernel/arch/i386/driver/serial.c | 59 ++++++++++++++++++++++++++++++++++++ src/kernel/arch/i386/driver/serial.h | 9 ++++++ src/kernel/arch/i386/tty/serial.c | 46 ---------------------------- src/kernel/arch/i386/tty/serial.h | 7 ----- src/kernel/arch/i386/tty/tty.c | 12 ++------ src/kernel/vfs/root.c | 25 ++++++++++++++- 6 files changed, 94 insertions(+), 64 deletions(-) create mode 100644 src/kernel/arch/i386/driver/serial.c create mode 100644 src/kernel/arch/i386/driver/serial.h delete mode 100644 src/kernel/arch/i386/tty/serial.c delete mode 100644 src/kernel/arch/i386/tty/serial.h diff --git a/src/kernel/arch/i386/driver/serial.c b/src/kernel/arch/i386/driver/serial.c new file mode 100644 index 0000000..d2c34e7 --- /dev/null +++ b/src/kernel/arch/i386/driver/serial.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +static const int COM1 = 0x3f8; + +static void serial_selftest(void) { + char b = 0x69; + port_out8(COM1 + 4, 0b00011110); // enable loopback mode + port_out8(COM1, b); + assert(port_in8(COM1) == b); +} + +void serial_init(void) { + // see https://www.sci.muni.cz/docs/pc/serport.txt + // set baud rate divisor + port_out8(COM1 + 3, 0b10000000); // enable DLAB + port_out8(COM1 + 0, 0x01); // divisor = 1 (low byte) + port_out8(COM1 + 1, 0x00); // (high byte) + + port_out8(COM1 + 3, 0b00000011); // 8 bits, no parity, one stop bit + port_out8(COM1 + 1, 0x01); // enable the Data Ready IRQ + port_out8(COM1 + 2, 0b11000111); // enable FIFO with 14-bit trigger level (???) + + serial_selftest(); + + port_out8(COM1 + 4, 0b00001111); // enable everything in the MCR +} + +static void serial_putchar(char c) { + while ((port_in8(COM1 + 5) & 0x20) == 0); // wait for THRE + port_out8(COM1, c); +} + +bool serial_poll_read(char *c) { + if ((port_in8(COM1 + 5) & 0x01) == 0) // needs DR + return false; + *c = port_in8(COM1); + return true; +} + +size_t serial_read(char *buf, size_t len) { + irq_interrupt_flag(true); + for (size_t i = 0; i < len; i++) { + for (;;) { + if (serial_poll_read(&buf[i])) break; + asm("hlt" ::: "memory"); + } + } + irq_interrupt_flag(false); + return len; +} + +void serial_write(const char *buf, size_t len) { + for (size_t i = 0; i < len; i++) + serial_putchar(buf[i]); +} diff --git a/src/kernel/arch/i386/driver/serial.h b/src/kernel/arch/i386/driver/serial.h new file mode 100644 index 0000000..be738d1 --- /dev/null +++ b/src/kernel/arch/i386/driver/serial.h @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +void serial_init(void); +size_t serial_read(char *buf, size_t len); +void serial_write(const char *buf, size_t len); + +bool serial_poll_read(char *c); diff --git a/src/kernel/arch/i386/tty/serial.c b/src/kernel/arch/i386/tty/serial.c deleted file mode 100644 index 054f956..0000000 --- a/src/kernel/arch/i386/tty/serial.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include - -static const int COM1 = 0x3f8; - -static void serial_selftest(void) { - char b = 0x69; - port_out8(COM1 + 4, 0b00011110); // enable loopback mode - port_out8(COM1, b); - assert(port_in8(COM1) == b); -} - -void serial_init(void) { - // see https://www.sci.muni.cz/docs/pc/serport.txt - // set baud rate divisor - port_out8(COM1 + 3, 0b10000000); // enable DLAB - port_out8(COM1 + 0, 0x01); // divisor = 1 (low byte) - port_out8(COM1 + 1, 0x00); // (high byte) - - port_out8(COM1 + 3, 0b00000011); // 8 bits, no parity, one stop bit - port_out8(COM1 + 1, 0x01); // enable the Data Ready IRQ - port_out8(COM1 + 2, 0b11000111); // enable FIFO with 14-bit trigger level (???) - - serial_selftest(); - - port_out8(COM1 + 4, 0b00001111); // enable everything in the MCR -} - -static void serial_putchar(char c) { - while ((port_in8(COM1 + 5) & 0x20) == 0); // wait for THRE - port_out8(COM1, c); -} - -bool serial_poll_read(char *c) { - if ((port_in8(COM1 + 5) & 0x01) == 0) // needs DR - return false; - *c = port_in8(COM1); - return true; -} - -void serial_write(const char *buf, size_t len) { - for (size_t i = 0; i < len; i++) - serial_putchar(buf[i]); -} diff --git a/src/kernel/arch/i386/tty/serial.h b/src/kernel/arch/i386/tty/serial.h deleted file mode 100644 index 808f1aa..0000000 --- a/src/kernel/arch/i386/tty/serial.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include -#include - -bool serial_poll_read(char *c); -void serial_write(const char *buf, size_t len); -void serial_init(void); diff --git a/src/kernel/arch/i386/tty/tty.c b/src/kernel/arch/i386/tty/tty.c index ebe0fd3..ab15aba 100644 --- a/src/kernel/arch/i386/tty/tty.c +++ b/src/kernel/arch/i386/tty/tty.c @@ -1,5 +1,4 @@ -#include -#include +#include #include #include @@ -13,14 +12,7 @@ void tty_init(void) { } void tty_read(char *buf, size_t len) { - irq_interrupt_flag(true); - for (size_t i = 0; i < len; i++) { - for (;;) { - if (serial_poll_read(&buf[i])) break; - asm("hlt" ::: "memory"); - } - } - irq_interrupt_flag(false); + serial_read(buf, len); } void tty_write(const char *buf, size_t len) { diff --git a/src/kernel/vfs/root.c b/src/kernel/vfs/root.c index 8904c4b..b8b41fc 100644 --- a/src/kernel/vfs/root.c +++ b/src/kernel/vfs/root.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -13,6 +14,7 @@ enum { HANDLE_ROOT, HANDLE_TTY, HANDLE_VGA, + HANDLE_COM1, HANDLE_PS2, HANDLE_ATA_ROOT, HANDLE_ATA, @@ -61,6 +63,7 @@ int vfs_root_handler(struct vfs_request *req) { if (exacteq(req, "/tty")) return HANDLE_TTY; if (exacteq(req, "/vga")) return HANDLE_VGA; + if (exacteq(req, "/com1")) return HANDLE_COM1; if (exacteq(req, "/ps2")) return HANDLE_PS2; if (exacteq(req, "/ata/")) return HANDLE_ATA_ROOT; @@ -79,7 +82,12 @@ int vfs_root_handler(struct vfs_request *req) { switch (req->id) { case HANDLE_ROOT: { // TODO document directory read format - const char src[] = "tty\0vga\0ata/"; + const char src[] = + "tty\0" + "vga\0" + "com1\0" + "ps2\0" + "ata/"; if (req->output.len < 0) return 0; // is this needed? TODO make that a size_t or something int len = min((size_t) req->output.len, sizeof(src)); virt_cpy_to(req->caller->pages, req->output.buf, src, len); @@ -100,6 +108,12 @@ int vfs_root_handler(struct vfs_request *req) { vga + req->offset, req->output.len); return req->output.len; } + case HANDLE_COM1: { + char buf[16]; + size_t len = serial_read(buf, sizeof buf); + virt_cpy_to(req->caller->pages, req->output.buf, buf, len); + return len; + } case HANDLE_PS2: { uint8_t buf[16]; size_t len = ps2_read(buf, sizeof buf); @@ -151,7 +165,16 @@ int vfs_root_handler(struct vfs_request *req) { req->input.buf, req->input.len); return req->input.len; } + case HANDLE_COM1: { + struct virt_iter iter; + virt_iter_new(&iter, req->input.buf, req->input.len, + req->caller->pages, true, false); + while (virt_iter_next(&iter)) + serial_write(iter.frag, iter.frag_len); + return iter.prior; + } case HANDLE_ATA_ROOT: return -1; + // TODO don't panic on ps2 reads default: panic_invalid_state(); } -- cgit v1.2.3