diff options
Diffstat (limited to 'src/kernel/HALKit/AMD64/HalDebugOutput.cpp')
| -rw-r--r-- | src/kernel/HALKit/AMD64/HalDebugOutput.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/kernel/HALKit/AMD64/HalDebugOutput.cpp b/src/kernel/HALKit/AMD64/HalDebugOutput.cpp new file mode 100644 index 00000000..dbddd092 --- /dev/null +++ b/src/kernel/HALKit/AMD64/HalDebugOutput.cpp @@ -0,0 +1,225 @@ +// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Licensed under the Apache License, Version 2.0 (see LICENSE file) +// Official repository: https://github.com/nekernel-org/nekernel + +#include <ArchKit/ArchKit.h> +#include <KernelKit/DebugOutput.h> +#include <NeKit/New.h> +#include <NeKit/Utils.h> +#include <modules/CoreGfx/CoreGfx.h> +#include <modules/CoreGfx/TextGfx.h> + +namespace Kernel { +enum CommStatus : UInt16 { + kStateInvalid = 0x64, + kStateReady = 0xCF, + kStateTransmit = 0xFC, + kStateCnt = 3 +}; + +namespace Detail { + constexpr ATTRIBUTE(unused) const UInt16 kPort = 0x3F8; + STATIC ATTRIBUTE(unused) UInt16 kState = kStateInvalid; + + /// @brief Init COM1. + /// @return + template <UInt16 PORT> + bool hal_serial_init() { + if (kState == kStateReady || kState == kStateTransmit) return true; + + HAL::rt_out8(PORT + 1, 0x00); // Disable all interrupts + HAL::rt_out8(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + HAL::rt_out8(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + HAL::rt_out8(PORT + 1, 0x00); // (hi byte) + HAL::rt_out8(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + HAL::rt_out8(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + HAL::rt_out8(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + HAL::rt_out8(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + HAL::rt_out8(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 (HAL::rt_in8(PORT) != 0xAE) { + return false; + } + + kState = kStateReady; + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + HAL::rt_out8(PORT + 4, 0x0F); + + return true; + } +} // namespace Detail + +TerminalDevice::~TerminalDevice() = default; + +#ifdef __DEBUG__ +STATIC SizeT kX = kFontSizeX, kY = kFontSizeY; +#endif // __DEBUG__ + +EXTERN_C void ke_utf_io_write(IDevice<const Utf8Char*>* obj, const Utf8Char* bytes) { + NE_UNUSED(bytes); + NE_UNUSED(obj); + +#ifdef __DEBUG__ + Detail::hal_serial_init<Detail::kPort>(); + + if (!bytes || Detail::kState != kStateReady) return; + + if (*bytes == 0) return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = urt_string_len(bytes); + + Char tmp_str[2]; + + while (index < len) { + if (bytes[index] == '\r') HAL::rt_out8(Detail::kPort, '\r'); + + HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]); + + tmp_str[0] = (bytes[index] > 127) ? '?' : bytes[index]; + tmp_str[1] = 0; + + cg_render_string(tmp_str, kY, kX, RGB(0xff, 0xff, 0xff)); + + if (bytes[index] == '\r') { + kY += kFontSizeY; + kX = kFontSizeX; + } + + kX += kFontSizeX; + + if (kX > kHandoverHeader->f_GOP.f_Width) { + kX = kFontSizeX; + } + + if (kY > kHandoverHeader->f_GOP.f_Height) { + kY = kFontSizeY; + + FBDrawInRegion(cg_get_clear_clr(), FB::CGAccessibilty::Height(), FB::CGAccessibilty::Width(), + 0, 0); + } + + ++index; + } + + Detail::kState = kStateReady; +#endif // __DEBUG__ +} + +EXTERN_C void ke_io_write(IDevice<const Char*>* obj, const Char* bytes) { + NE_UNUSED(bytes); + NE_UNUSED(obj); + +#ifdef __DEBUG__ + Detail::hal_serial_init<Detail::kPort>(); + + if (!bytes || Detail::kState != kStateReady) return; + + if (*bytes == 0) return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = rt_string_len(bytes); + + Char tmp_str[2]; + + while (index < len) { + if (bytes[index] == '\r') HAL::rt_out8(Detail::kPort, '\r'); + + HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]); + + tmp_str[0] = bytes[index]; + tmp_str[1] = 0; + + cg_render_string(tmp_str, kY, kX, RGB(0xff, 0xff, 0xff)); + + if (bytes[index] == '\r') { + kY += kFontSizeY; + kX = kFontSizeX; + } + + kX += kFontSizeX; + + if (kX > kHandoverHeader->f_GOP.f_Width) { + kX = kFontSizeX; + } + + if (kY > kHandoverHeader->f_GOP.f_Height) { + kY = kFontSizeY; + + FBDrawInRegion(cg_get_clear_clr(), FB::CGAccessibilty::Height(), FB::CGAccessibilty::Width(), + 0, 0); + } + + ++index; + } + + Detail::kState = kStateReady; +#endif // __DEBUG__ +} + +EXTERN_C void ke_io_read(IDevice<const Char*>*, const Char* bytes) { + NE_UNUSED(bytes); + +#ifdef __DEBUG__ + Detail::hal_serial_init<Detail::kPort>(); + + if (!bytes || Detail::kState != kStateReady) return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + + ///! TODO: Look on how to wait for the UART to complete. + while (true) { + auto in = HAL::rt_in8(Detail::kPort); + + ///! If enter pressed then break. + if (in == 0xD) { + break; + } + + if (in < '0' || in < 'A' || in < 'a') { + if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || in != ':') { + continue; + } + } + + ((char*) bytes)[index] = in; + + ++index; + } + + ((char*) bytes)[index] = 0; + + Detail::kState = kStateReady; +#endif // __DEBUG__ +} + +TerminalDevice TerminalDevice::The() { + TerminalDevice out(Kernel::ke_io_write, Kernel::ke_io_read); + return out; +} + +Utf8TerminalDevice::~Utf8TerminalDevice() = default; + +Utf8TerminalDevice Utf8TerminalDevice::The() { + Utf8TerminalDevice out(Kernel::ke_utf_io_write, + [](IDevice<const Utf8Char*>*, const Utf8Char*) -> Void {}); + return out; +} + +} // namespace Kernel |
