diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2025-01-01 08:01:48 -0500 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2025-01-01 08:01:48 -0500 |
commit | c459396945898c5c019a602a1f9bf742677de1c1 (patch) | |
tree | 58535052468574f9f805752eaf4eac6c7d004835 | |
parent | aaf7a356587b87a7edd09b59befdb1449010f6fc (diff) |
kernel: drivers: Implement serial driver.
It's a very primitive driver for outputting to serial console.
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | kernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | kernel/drivers/serial/serial.c | 70 | ||||
-rw-r--r-- | kernel/drivers/vga_text_buffer/vga_text_buffer.c | 6 | ||||
-rw-r--r-- | kernel/include/drivers/serial.h | 28 | ||||
-rw-r--r-- | kernel/include/kernel/io.h | 27 | ||||
-rw-r--r-- | kernel/kernel/io/io.c | 33 | ||||
-rw-r--r-- | kernel/kernel/kernel.c | 2 | ||||
-rw-r--r-- | kernel/libk/printk.c | 2 |
9 files changed, 170 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c1ac5b3..d07656d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(QEMU_SYSTEM_CMD qemu-system-i386) set(QEMU_ARGUMENTS -cdrom ${CMAKE_BINARY_DIR}/cmos.iso + -serial stdio ) add_custom_target(iso @@ -31,6 +32,7 @@ add_custom_target(run ${QEMU_ARGUMENTS} DEPENDS iso + USES_TERMINAL ) add_custom_target(run-gdb @@ -40,6 +42,7 @@ add_custom_target(run-gdb -S DEPENDS iso + USES_TERMINAL ) add_custom_target(clean-custom diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 0478740..206b728 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -7,8 +7,10 @@ set(KERNEL_SRC kernel/kernel.c kernel/halt.c kernel/stack_smashing_protector.c + kernel/io/io.c drivers/vga_text_buffer/vga_text_buffer.c + drivers/serial/serial.c libk/strlen.c libk/printk.c diff --git a/kernel/drivers/serial/serial.c b/kernel/drivers/serial/serial.c new file mode 100644 index 0000000..49362de --- /dev/null +++ b/kernel/drivers/serial/serial.c @@ -0,0 +1,70 @@ +/* + * CMOS + * Copyright (C) 2024 Raghuram Subramani <raghus2247@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <libk/string.h> + +#include <kernel/io.h> + +#include <drivers/serial.h> + +void +serial_initialize(void) +{ + outb(PORT + 1, 0x00); // Disable all interrupts + outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 1, 0x00); // (hi byte) + outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial + // returns same byte) + + // TODO: Check if serial is faulty (i.e: not same byte as sent) + /* if (inb(PORT + 0) != 0xAE) { + return 1; + } */ + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + outb(PORT + 4, 0x0F); +} + +static int +is_transmit_empty() +{ + return inb(PORT + 5) & 0x20; +} + +void +serial_write_char(char a) +{ + while (is_transmit_empty() == 0) + ; + + outb(PORT, a); +} + +void +serial_write_string(char *string) +{ + size_t size = strlen(string); + for (size_t i = 0; i < size; i++) + serial_write_char(string[i]); +} diff --git a/kernel/drivers/vga_text_buffer/vga_text_buffer.c b/kernel/drivers/vga_text_buffer/vga_text_buffer.c index 3a63ccb..d7aa235 100644 --- a/kernel/drivers/vga_text_buffer/vga_text_buffer.c +++ b/kernel/drivers/vga_text_buffer/vga_text_buffer.c @@ -89,9 +89,9 @@ vga_text_buffer_write_char(char c) } void -vga_text_buffer_write_string(char *data) +vga_text_buffer_write_string(char *string) { - size_t size = strlen(data); + size_t size = strlen(string); for (size_t i = 0; i < size; i++) - vga_text_buffer_write_char(data[i]); + vga_text_buffer_write_char(string[i]); } diff --git a/kernel/include/drivers/serial.h b/kernel/include/drivers/serial.h new file mode 100644 index 0000000..869500f --- /dev/null +++ b/kernel/include/drivers/serial.h @@ -0,0 +1,28 @@ +/* + * CMOS + * Copyright (C) 2024 Raghuram Subramani <raghus2247@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __drivers_serial_h +#define __drivers_serial_h + +#define PORT 0x3f8 // COM1 + +void serial_initialize(void); +void serial_write_char(char); +void serial_write_string(char *); + +#endif diff --git a/kernel/include/kernel/io.h b/kernel/include/kernel/io.h new file mode 100644 index 0000000..99a8aec --- /dev/null +++ b/kernel/include/kernel/io.h @@ -0,0 +1,27 @@ +/* + * CMOS + * Copyright (C) 2024 Raghuram Subramani <raghus2247@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __kernel_io_h +#define __kernel_io_h + +#include <stdint.h> + +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t val); + +#endif diff --git a/kernel/kernel/io/io.c b/kernel/kernel/io/io.c new file mode 100644 index 0000000..f8feb32 --- /dev/null +++ b/kernel/kernel/io/io.c @@ -0,0 +1,33 @@ +#include <stdint.h> + +#include <kernel/io.h> + +/* Sends a 8/16/32-bit value on a I/O location. Traditional names are outb, + * outw and outl respectively. The a modifier enforces val to be placed in the + * eax register before the asm command is issued and Nd allows for one-byte + * constant values to be assembled as constants, freeing the edx register for + * other cases. */ + +void +outb(uint16_t port, uint8_t val) +{ + __asm__ volatile("outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); + + /* There's an outb %al, $imm8 encoding, for compile-time constant port + * numbers that fit in 8b. (N constraint). Wider immediate constants would be + * truncated at assemble-time (e.g. "i" constraint). The outb %al, %dx + * encoding is the only option for all other cases. %1 expands to %dx because + * port is a uint16_t. %w1 could be used if we had the port number a wider + * C type */ +} + +/* Receives a 8/16/32-bit value from an I/O location. Traditional names are + * inb, inw and inl respectively. */ + +uint8_t +inb(uint16_t port) +{ + uint8_t ret; + __asm__ volatile("inb %w1, %b0" : "=a"(ret) : "Nd"(port) : "memory"); + return ret; +} diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c index 511f3c3..4da19c3 100644 --- a/kernel/kernel/kernel.c +++ b/kernel/kernel/kernel.c @@ -18,12 +18,14 @@ #include <libk/io.h> +#include <drivers/serial.h> #include <drivers/vga_text_buffer.h> void kernel_main(void) { vga_text_buffer_initialize(); + serial_initialize(); printk("kernel_main: Started\n"); } diff --git a/kernel/libk/printk.c b/kernel/libk/printk.c index f3a5085..4983c50 100644 --- a/kernel/libk/printk.c +++ b/kernel/libk/printk.c @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <drivers/serial.h> #include <drivers/vga_text_buffer.h> #include <libk/io.h> @@ -24,4 +25,5 @@ void printk(char *msg) { vga_text_buffer_write_string(msg); + serial_write_string(msg); } |