kernel/uart: Refactor code

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
This commit is contained in:
EnderIce2 2024-12-23 03:52:26 +02:00
parent 0807ea5a9a
commit 81af8a48cb
No known key found for this signature in database
GPG Key ID: 2EE20AF089811A5A
10 changed files with 102 additions and 249 deletions

View File

@ -27,48 +27,9 @@ NewLock(DebuggerLock);
extern bool serialports[8];
EXTERNC NIF void uart_wrapper(char c, void *unused)
EXTERNC NIF void uart_wrapper(char c, void *)
{
static int once = 0;
if (unlikely(!once++))
{
uint8_t com = inb(0x3F8);
if (com != 0xFF)
{
outb(s_cst(uint16_t, 0x3F8 + 1), 0x00); // Disable all interrupts
outb(s_cst(uint16_t, 0x3F8 + 3), 0x80); // Enable DLAB (set baud rate divisor)
outb(s_cst(uint16_t, 0x3F8 + 0), 0x1); // Set divisor to 1 (lo byte) 115200 baud
outb(s_cst(uint16_t, 0x3F8 + 1), 0x0); // (hi byte)
outb(s_cst(uint16_t, 0x3F8 + 3), 0x03); // 8 bits, no parity, one stop bit
outb(s_cst(uint16_t, 0x3F8 + 2), 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(s_cst(uint16_t, 0x3F8 + 4), 0x0B); // IRQs enabled, RTS/DSR set
/* FIXME https://wiki.osdev.org/Serial_Ports */
// outb(s_cst(uint16_t, 0x3F8 + 0), 0x1E);
// outb(s_cst(uint16_t, 0x3F8 + 0), 0xAE);
// Check if the serial port is faulty.
// if (inb(s_cst(uint16_t, 0x3F8 + 0)) != 0xAE)
// {
// static int once = 0;
// if (!once++)
// warn("Serial port %#llx is faulty.", 0x3F8);
// // serialports[0x3F8] = false; // ignore for now
// // return;
// }
// Set to normal operation mode.
outb(s_cst(uint16_t, 0x3F8 + 4), 0x0F);
serialports[0] = true;
}
}
if (likely(serialports[0]))
{
while ((inb(s_cst(uint16_t, 0x3F8 + 5)) & 0x20) == 0)
;
outb(0x3F8, c);
}
UNUSED(unused);
uart.DebugWrite(c);
}
static inline NIF bool WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, va_list args)

View File

@ -16,33 +16,22 @@
*/
#include <uart.hpp>
#include <io.h>
#include <debug.h>
#include <vector>
bool serialports[8] = {false, false, false, false, false, false, false, false};
std::vector<UniversalAsynchronousReceiverTransmitter::Events *> RegisteredEvents;
#if defined(__amd64__) || defined(__i386__)
NIF __always_inline inline uint8_t NoProfiler_inportb(uint16_t Port)
namespace UART
{
uint8_t Result;
asm("in %%dx, %%al"
: "=a"(Result)
: "d"(Port));
return Result;
}
enum SerialPorts
{
COM1 = 0x3F8,
COM2 = 0x2F8,
COM3 = 0x3E8,
COM4 = 0x2E8,
COM5 = 0x5F8,
COM6 = 0x4F8,
COM7 = 0x5E8,
COM8 = 0x4E8
};
NIF __always_inline inline void NoProfiler_outportb(uint16_t Port, uint8_t Data)
{
asmv("out %%al, %%dx"
:
: "a"(Data), "d"(Port));
}
#endif
namespace UniversalAsynchronousReceiverTransmitter
{
#define SERIAL_ENABLE_DLAB 0x80
#define SERIAL_RATE_115200_LO 0x01
#define SERIAL_RATE_115200_HI 0x00
@ -52,137 +41,96 @@ namespace UniversalAsynchronousReceiverTransmitter
#define SERIAL_RATE_38400_HI 0x00
#define SERIAL_BUFFER_EMPTY 0x20
/* TODO: Serial Port implementation needs reword. https://wiki.osdev.org/Serial_Ports */
nsa NIF UART::UART(SerialPorts Port)
void Driver::DebugWrite(uint8_t Char)
{
#if defined(__amd64__) || defined(__i386__)
if (Port == COMNULL)
return;
uint8_t com = NoProfiler_inportb(Port);
if (com == 0xFF)
{
error("Serial port %#lx is not available.", Port);
return;
}
this->Port = Port;
int PortNumber = 0;
switch (Port)
{
case COM1:
PortNumber = 0;
break;
case COM2:
PortNumber = 1;
break;
case COM3:
PortNumber = 2;
break;
case COM4:
PortNumber = 3;
break;
case COM5:
PortNumber = 4;
break;
case COM6:
PortNumber = 5;
break;
case COM7:
PortNumber = 6;
break;
case COM8:
PortNumber = 7;
break;
default:
return;
}
if (serialports[PortNumber])
return;
// Initialize the serial port
NoProfiler_outportb(s_cst(uint16_t, Port + 1), 0x00); // Disable all interrupts
NoProfiler_outportb(s_cst(uint16_t, Port + 3), SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor)
NoProfiler_outportb(s_cst(uint16_t, Port + 0), SERIAL_RATE_115200_LO); // Set divisor to 1 (lo byte) 115200 baud
NoProfiler_outportb(s_cst(uint16_t, Port + 1), SERIAL_RATE_115200_HI); // (hi byte)
NoProfiler_outportb(s_cst(uint16_t, Port + 3), 0x03); // 8 bits, no parity, one stop bit
NoProfiler_outportb(s_cst(uint16_t, Port + 2), 0xC7); // Enable FIFO, clear them, with 14-byte threshold
NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0B); // IRQs enabled, RTS/DSR set
/* FIXME https://wiki.osdev.org/Serial_Ports */
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0x1E);
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0xAE);
// Check if the serial port is faulty.
// if (NoProfiler_inportb(s_cst(uint16_t, Port + 0)) != 0xAE)
// {
// static int once = 0;
// if (!once++)
// warn("Serial port %#lx is faulty.", Port);
// // serialports[Port] = false; // ignore for now
// // return;
// }
// Set to normal operation mode.
NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0F);
serialports[PortNumber] = true;
this->IsAvailable = true;
#endif
}
nsa NIF UART::~UART() {}
nsa NIF void UART::Write(uint8_t Char)
{
if (!this->IsAvailable)
if (!DebugAvailable)
return;
#if defined(__amd64__) || defined(__i386__)
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & SERIAL_BUFFER_EMPTY) == 0)
while ((inb(s_cst(uint16_t, COM1 + 5)) & SERIAL_BUFFER_EMPTY) == 0)
;
NoProfiler_outportb(Port, Char);
outb(COM1, Char);
#endif
foreach (auto e in RegisteredEvents)
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
e->OnSent(Char);
}
nsa NIF uint8_t UART::Read()
uint8_t Driver::DebugRead()
{
if (!this->IsAvailable)
if (!DebugAvailable)
return 0;
#if defined(__amd64__) || defined(__i386__)
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & 1) == 0)
while ((inb(s_cst(uint16_t, COM1 + 5)) & 1) == 0)
;
return NoProfiler_inportb(Port);
return inb(COM1);
#endif
foreach (auto e in RegisteredEvents)
{
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
{
}
void Driver::TTYWrite(uint8_t Char)
{
if (!TTYAvailable)
return;
#if defined(__amd64__) || defined(__i386__)
e->OnReceived(NoProfiler_inportb(Port));
while ((inb(s_cst(uint16_t, COM4 + 5)) & SERIAL_BUFFER_EMPTY) == 0)
;
outb(COM4, Char);
#endif
}
}
}
nsa NIF Events::Events(SerialPorts Port)
uint8_t Driver::TTYRead()
{
this->Port = Port;
RegisteredEvents.push_back(this);
if (!TTYAvailable)
return 0;
#if defined(__amd64__) || defined(__i386__)
while ((inb(s_cst(uint16_t, COM4 + 5)) & 1) == 0)
;
return inb(COM4);
#endif
}
nsa NIF Events::~Events()
Driver::Driver()
{
forItr(itr, RegisteredEvents)
#if defined(__amd64__) || defined(__i386__)
auto initPort = [](uint16_t Port)
{
if (*itr == this)
{
RegisteredEvents.erase(itr);
return;
}
// Initialize the serial port
outb(s_cst(uint16_t, Port + 1), 0x00); // Disable all interrupts
outb(s_cst(uint16_t, Port + 3), SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor)
outb(s_cst(uint16_t, Port + 0), SERIAL_RATE_115200_LO); // Set divisor to 1 (lo byte) 115200 baud
outb(s_cst(uint16_t, Port + 1), SERIAL_RATE_115200_HI); // (hi byte)
outb(s_cst(uint16_t, Port + 3), 0x03); // 8 bits, no parity, one stop bit
outb(s_cst(uint16_t, Port + 2), 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(s_cst(uint16_t, Port + 4), 0x0B); // IRQs enabled, RTS/DSR set
/* FIXME https://wiki.osdev.org/Serial_Ports */
// outb(s_cst(uint16_t, Port + 0), 0x1E);
// outb(s_cst(uint16_t, Port + 0), 0xAE);
// Check if the serial port is faulty.
// if (inb(s_cst(uint16_t, Port + 0)) != 0xAE)
// {
// static int once = 0;
// if (!once++)
// warn("Serial port %#lx is faulty.", Port);
// // serialports[Port] = false; // ignore for now
// // return;
// }
// Set to normal operation mode.
outb(s_cst(uint16_t, Port + 4), 0x0F);
};
uint8_t com = inb(COM1);
if (com != 0xFF)
{
initPort(COM1);
DebugAvailable = true;
}
com = inb(COM4);
if (com != 0xFF)
{
initPort(COM4);
TTYAvailable = true;
}
#endif
}
Driver::~Driver() {}
}

View File

@ -20,70 +20,24 @@
#include <types.h>
namespace UniversalAsynchronousReceiverTransmitter
namespace UART
{
/**
* @brief Serial ports. (if available)
*/
enum SerialPorts
{
COMNULL = 0,
COM1 = 0x3F8,
COM2 = 0x2F8,
COM3 = 0x3E8,
COM4 = 0x2E8,
COM5 = 0x5F8,
COM6 = 0x4F8,
COM7 = 0x5E8,
COM8 = 0x4E8
};
class UART
class Driver
{
private:
SerialPorts Port;
bool IsAvailable;
bool DebugAvailable = false;
bool TTYAvailable = false;
public:
UART(SerialPorts Port = COMNULL);
~UART();
void Write(uint8_t Char);
uint8_t Read();
Driver();
~Driver();
void DebugWrite(uint8_t Char);
uint8_t DebugRead();
void TTYWrite(uint8_t Char);
uint8_t TTYRead();
};
class Events
{
private:
SerialPorts Port;
protected:
/**
* @brief UART events.
* @param Port if none, all ports are registered for events.
*/
Events(SerialPorts Port = COMNULL);
~Events();
public:
/**
* @brief Get the Registered Port object
* @return SerialPorts
*/
nsa NIF SerialPorts GetRegisteredPort() { return this->Port; }
/**
* @brief Called when a character is sent.
* @param Char the sent character.
*/
virtual void OnSent(uint8_t Char) { UNUSED(Char); }
/**
* @brief Called when a character is received.
* @param Char the received character.
*/
virtual void OnReceived(uint8_t Char) { UNUSED(Char); }
};
}
#endif // !__FENNIX_KERNEL_UART_H__

View File

@ -23,7 +23,6 @@
#include <ints.hpp>
#include <printf.h>
#include <lock.hpp>
#include <uart.hpp>
#include <kcon.hpp>
#include <debug.h>
#include <smp.hpp>
@ -60,6 +59,7 @@ Time::time *TimeManager = nullptr;
Tasking::Task *TaskManager = nullptr;
PCI::Manager *PCIManager = nullptr;
Driver::Manager *DriverManager = nullptr;
UART::Driver uart;
EXTERNC void putchar(char c)
{
@ -67,7 +67,7 @@ EXTERNC void putchar(char c)
if (vt != nullptr)
vt->Process(c);
else
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(c);
uart.DebugWrite(c);
}
EXTERNC void _KPrint(const char *Format, va_list Args)

View File

@ -33,6 +33,7 @@
#include <time.hpp>
#include <disk.hpp>
#include <kcon.hpp>
#include <uart.hpp>
#include <tty.hpp>
#include <pci.hpp>
#include <smp.hpp>
@ -51,8 +52,8 @@ extern Time::time *TimeManager;
extern PCI::Manager *PCIManager;
extern vfs::Virtual *fs;
extern Tasking::Task *TaskManager;
extern Driver::Manager *DriverManager;
extern UART::Driver uart;
#endif // __cplusplus

View File

@ -25,8 +25,6 @@
NewLock(DumperLock);
using namespace UniversalAsynchronousReceiverTransmitter;
int vprintf_dumper(const char *format, va_list list) { return vfctprintf(uart_wrapper, NULL, format, list); }
void WriteRaw(const char *format, ...)

View File

@ -27,8 +27,6 @@ TODO: This code is a mess. It needs to be cleaned up.
#include <printf.h>
#include <lock.hpp>
using namespace UniversalAsynchronousReceiverTransmitter;
NewLock(netdbg_lock);
namespace NetDbg

View File

@ -25,14 +25,11 @@ bool EnableProfiler = false;
bool Wait = false;
unsigned long long LogDepth = 0;
unsigned int Level = 0;
using namespace UniversalAsynchronousReceiverTransmitter;
UART com2(COM2);
static inline nsa NIF void profiler_uart_wrapper(char c, void *unused)
{
bool renable = EnableProfiler;
EnableProfiler = false;
com2.Write(c);
UNUSED(unused);
if (renable)
EnableProfiler = true;

View File

@ -21,8 +21,6 @@
#include "../kernel.h"
using namespace UniversalAsynchronousReceiverTransmitter;
#if BITS_PER_LONG >= 64
typedef long gcov_type;
#else
@ -57,7 +55,7 @@ struct gcov_info
static inline nsa NIF void gcov_uart_wrapper(char c, void *unused)
{
UART(COM2).Write(c);
UNUSED(c);
UNUSED(unused);
}

View File

@ -21,11 +21,9 @@
#include "../kernel.h"
using namespace UniversalAsynchronousReceiverTransmitter;
static inline nsa NIF void gprof_uart_wrapper(char c, void *unused)
{
UART(COM2).Write(c);
UNUSED(c);
UNUSED(unused);
}