aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2025-01-01 08:01:48 -0500
committerRaghuram Subramani <raghus2247@gmail.com>2025-01-01 08:01:48 -0500
commitc459396945898c5c019a602a1f9bf742677de1c1 (patch)
tree58535052468574f9f805752eaf4eac6c7d004835
parentaaf7a356587b87a7edd09b59befdb1449010f6fc (diff)
kernel: drivers: Implement serial driver.
It's a very primitive driver for outputting to serial console.
-rw-r--r--CMakeLists.txt3
-rw-r--r--kernel/CMakeLists.txt2
-rw-r--r--kernel/drivers/serial/serial.c70
-rw-r--r--kernel/drivers/vga_text_buffer/vga_text_buffer.c6
-rw-r--r--kernel/include/drivers/serial.h28
-rw-r--r--kernel/include/kernel/io.h27
-rw-r--r--kernel/kernel/io/io.c33
-rw-r--r--kernel/kernel/kernel.c2
-rw-r--r--kernel/libk/printk.c2
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);
}