From 609e10e13c9d30d7e4b907e9663e5b09205e1009 Mon Sep 17 00:00:00 2001 From: Tomas Date: Tue, 18 Feb 2025 14:06:41 +0100 Subject: [PATCH] Implemented serial driver --- kernel/include/serial.h | 19 +++++++++++++++ kernel/include/system.h | 16 +++++++++++++ kernel/src/entry.s | 10 ++++---- kernel/src/kernel.c | 14 ++++++++++- kernel/src/serial.c | 53 +++++++++++++++++++++++++++++++++++++++++ kernel/src/system.c | 39 ++++++++++++++++++++++++++++++ 6 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 kernel/include/serial.h create mode 100644 kernel/include/system.h create mode 100644 kernel/src/serial.c create mode 100644 kernel/src/system.c diff --git a/kernel/include/serial.h b/kernel/include/serial.h new file mode 100644 index 0000000..8ada96c --- /dev/null +++ b/kernel/include/serial.h @@ -0,0 +1,19 @@ +#ifndef _SERIAL_H +#define _SERIAL_H + +#include + +#define COM1 0x3f8 +#define COM2 0x2f8 +#define COM3 0x3e8 +#define COM4 0x2e8 + +int serial_init(int dev); +int serial_txem(int dev); +void serial_send(int dev, char data); +int serial_rcvd(int dev); +char serial_recv(int dev); +void serial_write(int dev, char* buf, size_t len); +void serial_print(int dev, char* s); + +#endif diff --git a/kernel/include/system.h b/kernel/include/system.h new file mode 100644 index 0000000..eb314b8 --- /dev/null +++ b/kernel/include/system.h @@ -0,0 +1,16 @@ +#ifndef _SYSTEM_H +#define _SYSTEM_H + +#include + +void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx); + +// Ports +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t data); +uint16_t inw(uint16_t port); +void outw(uint16_t port, uint16_t data); +uint32_t inl(uint16_t port); +void outl(uint16_t port, uint32_t data); + +#endif diff --git a/kernel/src/entry.s b/kernel/src/entry.s index 7e137df..b582dad 100644 --- a/kernel/src/entry.s +++ b/kernel/src/entry.s @@ -17,11 +17,12 @@ multiboot: dd FLAGS dd CHECK -; Initialize stack section .bss align 16 + +; Initialize stack stack_bottom: -resb 16384 ; 16kB + resb 16384 ; 16kB stack_top: ; Entry point @@ -29,9 +30,8 @@ section .text global _start extern kmain _start: - mov esp, stack_top - - call kmain ; Call kernel main + mov esp, stack_top ; Setup stack + call kmain ; Call kernel main ; Hang if kernel returns cli diff --git a/kernel/src/kernel.c b/kernel/src/kernel.c index b3a62a7..9408fea 100644 --- a/kernel/src/kernel.c +++ b/kernel/src/kernel.c @@ -1,13 +1,25 @@ #include +#include #include #define _hlt() while (1) __asm__ volatile ("cli; hlt"); __noreturn void kmain(void) { + serial_init(COM1); + serial_print(COM1, "kern.\n\n"); + while (1) { + char c = serial_recv(COM1); + serial_send(COM1, c); + if (c == '\r') { + serial_send(COM1, '\n'); + break; + } + } + tty_init(); tty_puts("Hello, World!\n"); - _hlt(); + panic("kmain() reached end!"); } diff --git a/kernel/src/serial.c b/kernel/src/serial.c new file mode 100644 index 0000000..d5cbb59 --- /dev/null +++ b/kernel/src/serial.c @@ -0,0 +1,53 @@ +#include +#include +#include + +int serial_init(int dev) { + outb(dev + 1, 0x00); // Disable serial interrupts + outb(dev + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(dev + 0, 0x03); // Set divisor to 3 (low byte) 38400 baud + outb(dev + 1, 0x00); // (high byte) + outb(dev + 3, 0x03); // 8 bits, no parity, one stop bit + outb(dev + 2, 0xC7); // Enable FIFO, clear them, with 14 byte threshold + outb(dev + 4, 0x0B); // IRQs enabled, RTS/DSR set + outb(dev + 4, 0x1E); // Set in loopback mode, test the serial chip + outb(dev + 0, 0xAE); // Test serial chip (send byte 0xAE and check if it returns) + + if (inb(dev + 0) != 0xAE) return 1; + outb(dev + 4, 0x0F); // non-loopback, IRQs enabled, OUT#1 and OUT#2 bits enabled + + return 0; +} + +int serial_txem(int dev) { + return inb(dev + 5) & 0x20; +} + +void serial_send(int dev, char data) { + while (serial_txem(dev) == 0); + outb(dev, data); +} + +int serial_rcvd(int dev) { + return inb(dev + 5) & 1; +} + +char serial_recv(int dev) { + while (serial_rcvd(dev) == 0); + return inb(dev); +} + +void serial_write(int dev, char* buf, size_t len) { + for (size_t i = 0; i < len; i++) { + if (buf[i] == '\n') serial_send(dev, '\r'); + serial_send(dev, buf[i]); + } +} + +void serial_print(int dev, char* s) { + size_t len = 0; + char* p = s; + while (*p++ != '\0') len++; + serial_write(dev, s, len); +} + diff --git a/kernel/src/system.c b/kernel/src/system.c new file mode 100644 index 0000000..f44c378 --- /dev/null +++ b/kernel/src/system.c @@ -0,0 +1,39 @@ +#include + +void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { + __asm__ volatile ("cpuid" + : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) + : "a"(*eax) + : "memory"); +} + +uint8_t inb(uint16_t port) { + uint8_t r; + __asm__ volatile ("inb %1, %0" : "=a"(r) : "dN"(port)); + return r; +} + +void outb(uint16_t port, uint8_t data) { + __asm__ volatile ("outb %1, %0" :: "dN"(port), "a"(data)); +} + +uint16_t inw(uint16_t port) { + uint16_t r; + __asm__ volatile ("inw %1, %0" : "=a"(r) : "dN"(port)); + return r; +} + +void outw(uint16_t port, uint16_t data) { + __asm__ volatile ("outw %1, %0" :: "dN"(port), "a"(data)); +} + +uint32_t inl(uint16_t port) { + uint32_t r; + __asm__ volatile ("inl %1, %0" : "=a"(r) : "dN"(port)); + return r; +} + +void outl(uint16_t port, uint32_t data) { + __asm__ volatile ("outl %1, %0" :: "dN"(port), "a"(data)); +} +