aboutsummaryrefslogtreecommitdiff
path: root/devices
diff options
context:
space:
mode:
authoraqua <aqua@iserlohn-fortress.net>2022-03-28 20:03:38 +0300
committeraqua <aqua@iserlohn-fortress.net>2022-08-12 10:13:59 +0300
commitedf9e71e2a7b6b89775c29cf28c19c6b89992c25 (patch)
tree3adbf944d9e47a743063487c4facb7eed1fbdee0 /devices
downloadkernel-edf9e71e2a7b6b89775c29cf28c19c6b89992c25.tar.xz
Initial commit
x86 kernel that prints a hello world message to com1
Diffstat (limited to 'devices')
-rw-r--r--devices/meson.build5
-rw-r--r--devices/uart_16550.c68
-rw-r--r--devices/uart_16550.h56
-rw-r--r--devices/vga.c35
-rw-r--r--devices/vga.h24
5 files changed, 188 insertions, 0 deletions
diff --git a/devices/meson.build b/devices/meson.build
new file mode 100644
index 0000000..c52c389
--- /dev/null
+++ b/devices/meson.build
@@ -0,0 +1,5 @@
+devices = declare_dependency(
+ sources: ['vga.c', 'uart_16550.c'],
+ include_directories: '.'
+)
+
diff --git a/devices/uart_16550.c b/devices/uart_16550.c
new file mode 100644
index 0000000..7cec968
--- /dev/null
+++ b/devices/uart_16550.c
@@ -0,0 +1,68 @@
+#include "uart_16550.h"
+#include <sys/io.h>
+
+int
+uart_init(enum UART port)
+{
+ outb(0x00, port + 1); // Disable all interrupts
+ outb(0x80, port + 3); // Enable DLAB (set baud rate divisor)
+ outb(0x03, port + 0); // Set divisor to 3 (lo byte) 38400 baud
+ outb(0x00, port + 1); // (hi byte)
+ outb(0x03, port + 3); // 8 bits, no parity, one stop bit
+ outb(0xc7, port + 2); // Enable FIFO, clear them, with 14-byte threshold
+ outb(0x0b, port + 4); // IRQs enabled, RTS/DSR set
+ outb(0x1e, port + 4); // Set in loopback mode, test the serial chip
+ outb(0xae, port + 0); // Test serial chip (send byte 0xAE and check if serial
+ // returns same byte)
+
+ // 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(0x0f, port + 4);
+ return 0;
+}
+
+int
+uart_thre(enum UART port)
+{
+ return inb(port + LineStatus) & THRE;
+}
+
+void
+uart_write(enum UART port, char a)
+{
+ while (uart_thre(port) == 0)
+ ;
+ outb(a, port);
+
+ if (a == '\n') {
+ while (uart_thre(port) == 0)
+ ;
+ outb('\r', port);
+ }
+}
+
+int
+uart_puts(enum UART port, const char *string, int length)
+{
+ int written = 0;
+
+ if (length == -1)
+ while (*string != '\0') {
+ uart_write(port, *string);
+ ++string;
+ ++written;
+ }
+
+ else
+ for (int i = 0; i < length; ++i) {
+ uart_write(port, string[i]);
+ ++written;
+ }
+
+ return written;
+}
diff --git a/devices/uart_16550.h b/devices/uart_16550.h
new file mode 100644
index 0000000..d053985
--- /dev/null
+++ b/devices/uart_16550.h
@@ -0,0 +1,56 @@
+#pragma once
+
+enum uart_16550_offset {
+ Data = 0, // read from receive buffer / write to transmit buffer | BaudDiv_l
+ InterruptControl = 1, // interrupt enable | BaudDiv_h
+ FifoControl = 2, // interrupt ID and FIFO control
+ LineControl = 3, // most significant bit is the DLAB
+ ModemControl = 4,
+ LineStatus = 5,
+ ModemStatus = 6,
+ Scratch = 7,
+};
+// Line Control
+// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+// |dla| | parity | s | data |
+
+enum LineControl {
+ d5bit = 0b00000000, // data bits
+ d6bit = 0b00000001,
+ d7bit = 0b00000010,
+ d8bit = 0b00000011,
+ // none = 0b00000000, // parity bits
+ odd = 0b00001000,
+ even = 0b00011000,
+ mark = 0b00101000,
+ space = 0b00111000,
+ // s1bit = 0b00000000, // stop bits
+ s2bit = 0b00000100, // 1.5 for 5bit data; 2 otherwise
+ dlab = 0b10000000, // divisor latch access bit
+};
+
+// Line Status Register
+enum LineStatus {
+ DR = 0b00000001, // data ready: see if there is data to read
+ OE = 0b00000010, // overrun error: see if there has been data lost
+ PE = 0b00000100, // parity error: see if there was error in transmission
+ FE = 0b00001000, // framing error: see if a stop bit was missing
+ BI = 0b00010000, // break indicator: see if there is a break in data input
+ THRE = 0b00100000, // transmitter holding register empty: see if transmission buffer is empty
+ TEMT = 0b01000000, // transmitter empty: see if transmitter is not doing anything
+ ERRO = 0b10000000, // impending error: see if there is an error with a word in the input buffer
+};
+
+enum UART {
+ COM1 = 0x3f8,
+ COM2 = 0x2f8,
+ COM3 = 0x3E8,
+ COM4 = 0x2E8,
+ COM5 = 0x5F8,
+ COM6 = 0x4F8,
+ COM7 = 0x5E8,
+ COM8 = 0x4E8,
+};
+
+int uart_init(enum UART port);
+int uart_puts(enum UART port, const char *string, int length);
diff --git a/devices/vga.c b/devices/vga.c
new file mode 100644
index 0000000..983e630
--- /dev/null
+++ b/devices/vga.c
@@ -0,0 +1,35 @@
+#include "vga.h"
+#include <stddef.h>
+#include <stdint.h>
+
+struct __attribute__((packed)) VGAEntry {
+ unsigned char text;
+ uint8_t foreground : 4;
+ uint8_t background : 4;
+};
+
+_Static_assert(sizeof(struct VGAEntry) == 2);
+
+const size_t width = 80;
+const size_t height = 25;
+
+struct VGAEntry *buffer;
+
+void
+vga_init()
+{
+ buffer = (struct VGAEntry *)0xc03ff000;
+ vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY);
+}
+
+void
+vga_clear(enum vga_color foreground, enum vga_color background)
+{
+ for (size_t y = 0; y < height; ++y)
+ for (size_t x = 0; x < width; ++x) {
+ const size_t index = y * width + x;
+ buffer[index].text = ' ';
+ buffer[index].foreground = foreground;
+ buffer[index].background = background;
+ }
+}
diff --git a/devices/vga.h b/devices/vga.h
new file mode 100644
index 0000000..c2ef2ef
--- /dev/null
+++ b/devices/vga.h
@@ -0,0 +1,24 @@
+#pragma once
+
+/* Hardware text mode color constants. */
+enum vga_color {
+ VGA_COLOR_BLACK = 0,
+ VGA_COLOR_BLUE = 1,
+ VGA_COLOR_GREEN = 2,
+ VGA_COLOR_CYAN = 3,
+ VGA_COLOR_RED = 4,
+ VGA_COLOR_MAGENTA = 5,
+ VGA_COLOR_BROWN = 6,
+ VGA_COLOR_LIGHT_GREY = 7,
+ VGA_COLOR_DARK_GREY = 8,
+ VGA_COLOR_LIGHT_BLUE = 9,
+ VGA_COLOR_LIGHT_GREEN = 10,
+ VGA_COLOR_LIGHT_CYAN = 11,
+ VGA_COLOR_LIGHT_RED = 12,
+ VGA_COLOR_LIGHT_MAGENTA = 13,
+ VGA_COLOR_LIGHT_BROWN = 14,
+ VGA_COLOR_WHITE = 15,
+};
+
+void vga_init();
+void vga_clear(enum vga_color foreground, enum vga_color background);