From 16ab26257e1ba704988ed9a1e703d3ac04aece34 Mon Sep 17 00:00:00 2001 From: Tyler McGurrin Date: Sat, 31 May 2025 11:59:11 -0400 Subject: [PATCH] Pretty Much Finish Basic Serial Driver --- build.sh | 7 +- src/kernel/dri/serial.c | 277 +++++++++++++++++++++++++++++++++++++++- src/kernel/dri/serial.h | 26 +++- src/kernel/main.c | 6 +- src/libs/version.h | 2 +- 5 files changed, 313 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 2ca139d..12ca553 100755 --- a/build.sh +++ b/build.sh @@ -38,7 +38,12 @@ case $yn in echo ------------- echo STARTING QEMU echo ------------- - qemu-system-i386 -audiodev pa,id=speaker -machine pcspk-audiodev=speaker -fda build/main_floppy.img + qemu-system-i386 -chardev pty,id=serial1 \ + -serial mon:stdio \ + -serial chardev:serial1 \ + -audiodev pa,id=speaker \ + -machine pcspk-audiodev=speaker \ + -fda build/main_floppy.img echo -------- echo Finshed! echo -------- diff --git a/src/kernel/dri/serial.c b/src/kernel/dri/serial.c index 60e9c6c..438a890 100644 --- a/src/kernel/dri/serial.c +++ b/src/kernel/dri/serial.c @@ -3,4 +3,279 @@ |Copyright (C) 2025| |Tyler McGurrin | \*----------------*/ -#include "serial.h" \ No newline at end of file +#include "serial.h" + +#include +#include +#include +#include + +char Serial_Read_Buffer; +char Serial_Write_Buffer; + +/* +IO Port Offset Setting of DLAB I/O Access Register mapped to this port + +0 0 Read Receive buffer. + +0 0 Write Transmit buffer. + +1 0 Read/Write Interrupt Enable Register. + +0 1 Read/Write With DLAB set to 1, this is the least significant byte of the divisor value for setting the baud rate. + +1 1 Read/Write With DLAB set to 1, this is the most significant byte of the divisor value. + +2 - Read Interrupt Identification + +2 - Write FIFO control registers + +3 - Read/Write Line Control Register. The most significant bit of this register is the DLAB. + +4 - Read/Write Modem Control Register. + +5 - Read Line Status Register. + +6 - Read Modem Status Register. + +7 - Read/Write Scratch Register. +*/ + + +// Cannot Figure out what part of spec triggers this, +// OSDEV wiki just says it exists thats about it... +void COM1_Serial_Handler() +{ + // Serial_Read_Buffer = Read_Serial(COM1_PORT); + // printf("Serial Read Buffer: %s", Serial_Read_Buffer); + printf("IRQ 4 Triggered!"); +} + +int Init_Serial(uint16_t COM_Port, int Baud) +{ + uint8_t Divisor = 115200 / Baud; + + i686_outb(COM_Port + 1, 0x00); // Disable all interrupts + i686_outb(COM_Port + 3, Divisor); // Enable DLAB (set baud rate divisor) + i686_outb(COM_Port + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + i686_outb(COM_Port + 1, 0x00); // (hi byte) + i686_outb(COM_Port + 3, 0x03); // 8 bits, no parity, one stop bit + i686_outb(COM_Port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + i686_outb(COM_Port + 4, 0x0B); // IRQs enabled, RTS/DSR set + i686_outb(COM_Port + 4, 0x1E); // Set in loopback mode, test the serial chip + i686_outb(COM_Port + 0, 0xAE); // 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(i686_inb(COM_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) + i686_outb(COM_Port + 4, 0x0F); + return 0; +} + +int Serial_Received(uint16_t COM_Port) +{ + return i686_inb(COM_Port + 5) & 1; +} + +char Read_Serial(uint16_t COM_Port) +{ + while (Serial_Received(COM_Port) == 0); + + return i686_inb(COM_Port); +} + +int Serial_Transmit_Empty(uint16_t COM_Port) +{ + return i686_inb(COM_Port + 5) & 0x20; +} + +void Write_Serial(uint16_t COM_Port, char a) +{ + while (Serial_Transmit_Empty(COM_Port) == 0); + + i686_outb(COM_Port,a); +} +// We do the funny... +extern const char g_HexChars[]; + +void Serial_Puts(uint16_t COM_Port, const char* str) +{ + while(*str) + { + Write_Serial(COM_Port, *str); + str++; + } +} + +void Serial_Printf_Unsigned(uint16_t COM_Port,unsigned long long number, int radix) +{ + char buffer[32]; + int pos = 0; + + //number to ASCII conversion + do { + unsigned long long rem = number % radix; + number /= radix; + buffer[pos++] = g_HexChars[rem]; + } while (number > 0); + + //print number in reverse order + while (--pos >= 0) + Write_Serial(COM_Port, buffer[pos]); +} + +void Serial_Printf_Signed(uint16_t COM_Port,long long number, int radix) +{ + if (number < 0) + { + Write_Serial(COM_Port, '-'); + Serial_Printf_Unsigned(COM_Port, -number, radix); + } + else Serial_Printf_Unsigned(COM_Port, number, radix); + +} + + +#define PRINTF_STATE_NORMAL 0 +#define PRINTF_STATE_LENGTH 1 +#define PRINTF_STATE_LENGTH_SHORT 2 +#define PRINTF_STATE_LENGTH_LONG 3 +#define PRINTF_STATE_SPEC 4 + +#define PRINTF_LENGTH_DEFAULT 0 +#define PRINTF_LENGTH_SHORT_SHORT 1 +#define PRINTF_LENGTH_SHORT 2 +#define PRINTF_LENGTH_LONG 3 +#define PRINTF_LENGTH_LONG_LONG 4 + +void Serial_Printf(uint16_t COM_Port, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + int state = PRINTF_STATE_NORMAL; + int length = PRINTF_LENGTH_DEFAULT; + int radix = 10; + bool sign = false; + bool number = false; + + while (*fmt) + { + switch (state) + { + case PRINTF_STATE_NORMAL: + switch (*fmt) + { + case '%': state = PRINTF_STATE_LENGTH; + break; + default: Write_Serial(COM_Port, *fmt); + break; + } + break; + + case PRINTF_STATE_LENGTH: + switch (*fmt) + { + case 'h': length = PRINTF_LENGTH_SHORT; + state = PRINTF_STATE_LENGTH_SHORT; + break; + case 'l': length = PRINTF_LENGTH_LONG; + state = PRINTF_STATE_LENGTH_LONG; + break; + default: goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_LENGTH_SHORT: + if (*fmt == 'h') + { + length = PRINTF_LENGTH_SHORT_SHORT; + state = PRINTF_STATE_SPEC; + } + else goto PRINTF_STATE_SPEC_; + break; + + case PRINTF_STATE_LENGTH_LONG: + if (*fmt == 'l') + { + length = PRINTF_LENGTH_LONG_LONG; + state = PRINTF_STATE_SPEC; + } + else goto PRINTF_STATE_SPEC_; + break; + + case PRINTF_STATE_SPEC: + PRINTF_STATE_SPEC_: + switch (*fmt) + { + case 'c': Write_Serial(COM_Port, (char)va_arg(args, int)); + break; + + case 's': + Serial_Puts(COM_Port, va_arg(args, const char*)); + break; + + case '%': Write_Serial(COM_Port, '%'); + break; + + case 'd': + case 'i': radix = 10; sign = true; number = true; + break; + + case 'u': radix = 10; sign = false; number = true; + break; + + case 'X': + case 'x': + case 'p': radix = 16; sign = false; number = true; + break; + + case 'o': radix = 8; sign = false; number = true; + break; + + // ignore invalid spec + default: break; + } + + if (number) + { + if (sign) + { + switch (length) + { + case PRINTF_LENGTH_SHORT_SHORT: + case PRINTF_LENGTH_SHORT: + case PRINTF_LENGTH_DEFAULT: Serial_Printf_Signed(COM_Port, va_arg(args, int), radix); + break; + + case PRINTF_LENGTH_LONG: Serial_Printf_Signed(COM_Port, va_arg(args, long), radix); + break; + + case PRINTF_LENGTH_LONG_LONG: Serial_Printf_Signed(COM_Port, va_arg(args, long long), radix); + break; + } + } + else + { + switch (length) + { + case PRINTF_LENGTH_SHORT_SHORT: + case PRINTF_LENGTH_SHORT: + case PRINTF_LENGTH_DEFAULT: Serial_Printf_Unsigned(COM_Port, va_arg(args, unsigned int), radix); + break; + + case PRINTF_LENGTH_LONG: Serial_Printf_Unsigned(COM_Port, va_arg(args, unsigned long), radix); + break; + + case PRINTF_LENGTH_LONG_LONG: Serial_Printf_Unsigned(COM_Port, va_arg(args, unsigned long long), radix); + break; + } + } + } + + // reset state + state = PRINTF_STATE_NORMAL; + length = PRINTF_LENGTH_DEFAULT; + radix = 10; + sign = false; + number = false; + break; + } + + fmt++; + } + + va_end(args); +} \ No newline at end of file diff --git a/src/kernel/dri/serial.h b/src/kernel/dri/serial.h index 9d63cd8..2a086d4 100644 --- a/src/kernel/dri/serial.h +++ b/src/kernel/dri/serial.h @@ -3,4 +3,28 @@ |Copyright (C) 2025| |Tyler McGurrin | \*----------------*/ -#pragma once \ No newline at end of file +#pragma once + +#include + +// You can really only trust the first and 2nd COM port addresses... +// fun. +enum COMPorts +{ + COM1_PORT = 0x3F8, + COM2_PORT = 0x2F8, + COM3_PORT = 0x3E8, + COM4_PORT = 0x2E8, + COM5_PORT = 0x5F8, + COM6_PORT = 0x4F8, + COM7_PORT = 0x5E8, + COM8_PORT = 0x4E8 +}; + +void COM1_Serial_Handler(); +int Serial_Received(uint16_t COM_Port); +char Read_Serial(uint16_t COM_Port); +int Serial_Transmit_Empty(uint16_t COM_Port); +void Write_Serial(uint16_t COM_Port, char a); +int Init_Serial(uint16_t COM_Port, int Baud); +void Serial_Printf(uint16_t COM_Port, const char* fmt, ...); \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index 7ec2c21..55b6657 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -57,8 +58,10 @@ void __attribute__((section(".entry"))) start(BootParams* bootParams) { HAL_Initialize(); movecursorpos(19, 8); printf("Done!\n\n\n\n\n"); + Init_Serial(COM1_PORT, 9600); i686_IRQ_RegisterHandler(0, timer); i686_IRQ_RegisterHandler(8, CMOS_RTC_Handler); + i686_IRQ_RegisterHandler(4, COM1_Serial_Handler); // Begin Loading Basic Drivers printf("Load Keyboard Driver..."); @@ -72,7 +75,8 @@ void __attribute__((section(".entry"))) start(BootParams* bootParams) { slaveFDDType = Slave_FDD_Detect(); Floppy_Drive_Start(1); Print_Storage_Types(masterFDDType, slaveFDDType); - printf("Kernel Params: %s\n", bootParams->KernelParams); + // printf("Kernel Params: %s\n", bootParams->KernelParams); + Serial_Printf(COM1_PORT, "Hello World!"); diff --git a/src/libs/version.h b/src/libs/version.h index f113e79..940dd9a 100644 --- a/src/libs/version.h +++ b/src/libs/version.h @@ -6,5 +6,5 @@ #pragma once #define LOGO " _ _____ _ __________________\n / | / / | / | / / _/_ __/ ____/\n / |/ / /| | / |/ // / / / / __/ \n / /| / ___ |/ /| // / / / / /___ \n/_/ |_/_/ |_/_/ |_/___/ /_/ /_____/ \n" -#define VERSION "RD-00020" +#define VERSION "RD-00023" #define BOOTLOGO " _ ______ ____ ____ ______\n / | / / __ )/ __ \\/ __ /_ __/\n / |/ / __ / / / / / / // / \n / /| / /_/ / /_/ / /_/ // / \n/_/ |_/_____/\\____/\\____//_/ \n"