diff --git a/CREDITS.md b/CREDITS.md index 5fad282c..0d2a9d29 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -12,6 +12,9 @@ License information can be found in the [LICENSES.md](LICENSES.md) file. - [ToaruOS](https://github.com/klange/toaruos) - [Various SIMD functions](https://wiki.osdev.org/User:01000101/optlib/) +## Virtual terminal +- [vtconsole](https://github.com/sleepy-monax/vtconsole) + ## Font - [Tamsyn Font](http://www.fial.com/~scott/tamsyn-font/) @@ -111,6 +114,9 @@ License information can be found in the [LICENSES.md](LICENSES.md) file. - [PS/2 Controller on OSDev](https://wiki.osdev.org/%228042%22_PS/2_Controller) - [AIP on OSDev](https://wiki.osdev.org/Advanced_Integrated_Peripheral) +## UART +- [Interfacing the Serial / RS232 Port V5.0](http://www.senet.com.au/~cpeacock) + --- Special thanks to all contributors and the creators of the referenced projects and resources! diff --git a/arch/amd64/cpu/apic.cpp b/arch/amd64/cpu/apic.cpp index 3340c5b2..c0588bc9 100644 --- a/arch/amd64/cpu/apic.cpp +++ b/arch/amd64/cpu/apic.cpp @@ -478,7 +478,7 @@ namespace APIC trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks); - KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks); + KPrint("APIC Timer: \x1b[1;32m%ld\x1b[0m ticks.", Ticks); } Timer::~Timer() diff --git a/arch/amd64/cpu/idt.cpp b/arch/amd64/cpu/idt.cpp index 3bec1dd8..43ac1ac2 100644 --- a/arch/amd64/cpu/idt.cpp +++ b/arch/amd64/cpu/idt.cpp @@ -577,7 +577,7 @@ namespace InterruptDescriptorTable #ifdef DEBUG EnableISRs = !DebuggerIsAttached; if (!EnableISRs) - KPrint("\eFFA500The debugger is attached, disabling all ISRs."); + KPrint("\x1b[34mThe debugger is attached, disabling all ISRs."); #endif /* ISR */ diff --git a/arch/amd64/cpu/smp.cpp b/arch/amd64/cpu/smp.cpp index 93ff23c0..d4c765a4 100644 --- a/arch/amd64/cpu/smp.cpp +++ b/arch/amd64/cpu/smp.cpp @@ -89,7 +89,7 @@ extern "C" void StartCPU() asmv("mov %0, %%rsp" ::"r"((&CPUs[CoreID])->Stack)); CPU::Interrupts(CPU::Enable); - KPrint("\e058C19CPU \e8888FF%d \e058C19is online", CoreID); + KPrint("CPU %d is online", CoreID); CPUEnabled.store(true, std::memory_order_release); CPU::Halt(true); } @@ -177,7 +177,7 @@ namespace SMP if (TimeManager->GetCounter() > Timeout) { error("CPU %d failed to load!", lapic->APICId); - KPrint("\eFF8C19CPU \e8888FF%d \eFF8C19failed to load!", + KPrint("\x1b[1;37;41mCPU %d failed to load!", lapic->APICId); break; } @@ -187,7 +187,7 @@ namespace SMP CPUEnabled.store(false, std::memory_order_release); } else - KPrint("\e058C19CPU \e8888FF%d \e058C19is the BSP", lapic->APICId); + KPrint("CPU %d is the BSP", lapic->APICId); } KernelAllocator.FreePages(CPUTmpStack, TO_PAGES(STACK_SIZE + 1)); diff --git a/arch/amd64/madt.cpp b/arch/amd64/madt.cpp index 03326a33..eaf2b011 100644 --- a/arch/amd64/madt.cpp +++ b/arch/amd64/madt.cpp @@ -46,7 +46,7 @@ namespace ACPI if (ptr[4] & 1) { lapic.push_back((LocalAPIC *)ptr); - KPrint("Local APIC \e8888FF%d\eCCCCCC (APIC \e8888FF%d\eCCCCCC) found.", lapic.back()->ACPIProcessorId, lapic.back()->APICId); + KPrint("Local APIC %d (APIC %d) found.", lapic.back()->ACPIProcessorId, lapic.back()->APICId); CPUCores++; } break; @@ -54,34 +54,34 @@ namespace ACPI case 1: { ioapic.push_back((MADTIOApic *)ptr); - KPrint("I/O APIC \e8888FF%d\eCCCCCC (Address \e8888FF%#lx\eCCCCCC) found.", ioapic.back()->APICID, ioapic.back()->Address); + KPrint("I/O APIC %d (Address %#lx) found.", ioapic.back()->APICID, ioapic.back()->Address); Memory::Virtual(KernelPageTable).Map((void *)(uintptr_t)ioapic.back()->Address, (void *)(uintptr_t)ioapic.back()->Address, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped. break; } case 2: { iso.push_back((MADTIso *)ptr); - KPrint("ISO (IRQ:\e8888FF%#lx\eCCCCCC, BUS:\e8888FF%#lx\eCCCCCC, GSI:\e8888FF%#lx\eCCCCCC, %s\eCCCCCC/%s\eCCCCCC) found.", + KPrint("ISO (IRQ:%#lx, BUS:%#lx, GSI:%#lx, %s/%s) found.", iso.back()->IRQSource, iso.back()->BuSSource, iso.back()->GSI, - iso.back()->Flags & 0x00000004 ? "\e1770FFActive High" : "\e475EFFActive Low", - iso.back()->Flags & 0x00000100 ? "\e00962DEdge Triggered" : "\e008F58Level Triggered"); + iso.back()->Flags & 0x00000004 ? "Active High" : "Active Low", + iso.back()->Flags & 0x00000100 ? "Edge Triggered" : "Level Triggered"); break; } case 4: { nmi.push_back((MADTNmi *)ptr); - KPrint("NMI \e8888FF%#lx\eCCCCCC (lint:\e8888FF%#lx\eCCCCCC) found.", nmi.back()->processor, nmi.back()->lint); + KPrint("NMI %#lx (lint:%#lx) found.", nmi.back()->processor, nmi.back()->lint); break; } case 5: { LAPICAddress = (LAPIC *)ptr; - KPrint("APIC found at \e8888FF%#lx\eCCCCCC", LAPICAddress); + KPrint("APIC found at %#lx", LAPICAddress); break; } default: { - KPrint("Unknown MADT entry \e8888FF%#lx\eCCCCCC", *(ptr)); + KPrint("Unknown MADT entry %#lx", *(ptr)); break; } } diff --git a/arch/i386/cpu/apic.cpp b/arch/i386/cpu/apic.cpp index 6996e036..a0dd750b 100644 --- a/arch/i386/cpu/apic.cpp +++ b/arch/i386/cpu/apic.cpp @@ -400,7 +400,7 @@ namespace APIC this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks)); this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw)); trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks); - KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks); + KPrint("APIC Timer: \x1b[1;32m%ld\x1b[0m ticks.", Ticks); } Timer::~Timer() diff --git a/arch/i386/cpu/idt.cpp b/arch/i386/cpu/idt.cpp index b5d1f09e..497f6337 100644 --- a/arch/i386/cpu/idt.cpp +++ b/arch/i386/cpu/idt.cpp @@ -464,7 +464,7 @@ namespace InterruptDescriptorTable // #ifdef DEBUG EnableISRs = !DebuggerIsAttached; if (!EnableISRs) - KPrint("\eFFA500The debugger is attached, disabling all ISRs."); + KPrint("\x1b[34mThe debugger is attached, disabling all ISRs."); // #endif SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE); diff --git a/arch/i386/madt.cpp b/arch/i386/madt.cpp index 61fcff86..b3ceea34 100644 --- a/arch/i386/madt.cpp +++ b/arch/i386/madt.cpp @@ -40,7 +40,7 @@ namespace ACPI if (ptr[4] & 1) { lapic.push_back((LocalAPIC *)ptr); - KPrint("Local APIC \e8888FF%d\eCCCCCC (APIC \e8888FF%d\eCCCCCC) found.", lapic.back()->ACPIProcessorId, lapic.back()->APICId); + KPrint("Local APIC %d (APIC %d) found.", lapic.back()->ACPIProcessorId, lapic.back()->APICId); CPUCores++; } break; @@ -48,34 +48,34 @@ namespace ACPI case 1: { ioapic.push_back((MADTIOApic *)ptr); - KPrint("I/O APIC \e8888FF%d\eCCCCCC (Address \e8888FF%#lx\eCCCCCC) found.", ioapic.back()->APICID, ioapic.back()->Address); + KPrint("I/O APIC %d (Address %#lx) found.", ioapic.back()->APICID, ioapic.back()->Address); Memory::Virtual(KernelPageTable).Map((void *)(uintptr_t)ioapic.back()->Address, (void *)(uintptr_t)ioapic.back()->Address, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped. break; } case 2: { iso.push_back((MADTIso *)ptr); - KPrint("ISO (IRQ:\e8888FF%#lx\eCCCCCC, BUS:\e8888FF%#lx\eCCCCCC, GSI:\e8888FF%#lx\eCCCCCC, %s\eCCCCCC/%s\eCCCCCC) found.", + KPrint("ISO (IRQ:%#lx, BUS:%#lx, GSI:%#lx, %s/%s) found.", iso.back()->IRQSource, iso.back()->BuSSource, iso.back()->GSI, - iso.back()->Flags & 0x00000004 ? "\e1770FFActive High" : "\e475EFFActive Low", - iso.back()->Flags & 0x00000100 ? "\e00962DEdge Triggered" : "\e008F58Level Triggered"); + iso.back()->Flags & 0x00000004 ? "Active High" : "Active Low", + iso.back()->Flags & 0x00000100 ? "Edge Triggered" : "Level Triggered"); break; } case 4: { nmi.push_back((MADTNmi *)ptr); - KPrint("NMI \e8888FF%#lx\eCCCCCC (lint:\e8888FF%#lx\eCCCCCC) found.", nmi.back()->processor, nmi.back()->lint); + KPrint("NMI %#lx (lint:%#lx) found.", nmi.back()->processor, nmi.back()->lint); break; } case 5: { LAPICAddress = (LAPIC *)ptr; - KPrint("APIC found at \e8888FF%#lx\eCCCCCC", LAPICAddress); + KPrint("APIC found at %#lx", LAPICAddress); break; } default: { - KPrint("Unknown MADT entry \e8888FF%#lx\eCCCCCC", *(ptr)); + KPrint("Unknown MADT entry %#lx", *(ptr)); break; } } diff --git a/core/console.cpp b/core/console.cpp index 7294ae2e..6d0ef6a8 100644 --- a/core/console.cpp +++ b/core/console.cpp @@ -21,32 +21,21 @@ #include #include #include +#include + +#include "../kernel.h" namespace KernelConsole { - termios term{}; - winsize termSize{}; - - ssize_t KConRead(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) - { - fixme("Reading %d bytes... \"%.*s\"", Size, Size, (char *)Buffer); - return Size; - } - - ssize_t KConWrite(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) - { - fixme("Writing %d bytes... \"%.*s\"", Size, Size, (char *)Buffer); - return Size; - } - int KConIoctl(struct Inode *Node, unsigned long Request, void *Argp) { + fixme("KConIoctl"); switch (Request) { case TCGETS: { struct termios *t = (struct termios *)Argp; - memcpy(t, &term, sizeof(struct termios)); + // memcpy(t, &term, sizeof(struct termios)); return 0; } case TCSETS: @@ -55,7 +44,7 @@ namespace KernelConsole return -EINVAL; struct termios *t = (struct termios *)Argp; - memcpy(&term, t, sizeof(struct termios)); + // memcpy(&term, t, sizeof(struct termios)); return 0; } case TIOCGPGRP: @@ -71,7 +60,7 @@ namespace KernelConsole case TIOCGWINSZ: { struct winsize *ws = (struct winsize *)Argp; - memcpy(ws, &termSize, sizeof(struct winsize)); + // memcpy(ws, &termSize, sizeof(struct winsize)); return 0; } case TIOCSWINSZ: @@ -80,7 +69,7 @@ namespace KernelConsole return -EINVAL; struct winsize *ws = (struct winsize *)Argp; - memcpy(&termSize, ws, sizeof(struct winsize)); + // memcpy(&termSize, ws, sizeof(struct winsize)); return 0; } case TCSETSW: @@ -132,41 +121,324 @@ namespace KernelConsole return 0; } + int TermColors[] = { + [TerminalColor::BLACK] = 0x000000, + [TerminalColor::RED] = 0xAA0000, + [TerminalColor::GREEN] = 0x00AA00, + [TerminalColor::YELLOW] = 0xAA5500, + [TerminalColor::BLUE] = 0x0000AA, + [TerminalColor::MAGENTA] = 0xAA00AA, + [TerminalColor::CYAN] = 0x00AAAA, + [TerminalColor::GREY] = 0xAAAAAA, + }; + + int TermBrightColors[] = { + [TerminalColor::BLACK] = 0x858585, + [TerminalColor::RED] = 0xFF5555, + [TerminalColor::GREEN] = 0x55FF55, + [TerminalColor::YELLOW] = 0xFFFF55, + [TerminalColor::BLUE] = 0x5555FF, + [TerminalColor::MAGENTA] = 0xFF55FF, + [TerminalColor::CYAN] = 0x55FFFF, + [TerminalColor::GREY] = 0xFFFFFF, + }; + + __no_sanitize("undefined") char FontRenderer::Paint(long CellX, long CellY, char Char, uint32_t Foreground, uint32_t Background) + { + uint64_t x = CellX * CurrentFont->GetInfo().Width; + uint64_t y = CellY * CurrentFont->GetInfo().Height; + + switch (CurrentFont->GetInfo().Type) + { + case Video::FontType::PCScreenFont1: + { + uint32_t *PixelPtr = (uint32_t *)Display->GetBuffer; + char *FontPtr = (char *)CurrentFont->GetInfo().PSF1Font->GlyphBuffer + (Char * CurrentFont->GetInfo().PSF1Font->Header->charsize); + for (uint64_t Y = 0; Y < 16; Y++) + { + for (uint64_t X = 0; X < 8; X++) + { + if ((*FontPtr & (0b10000000 >> X)) > 0) + *(unsigned int *)(PixelPtr + (x + X) + ((y + Y) * Display->GetWidth)) = Foreground; + else + *(unsigned int *)(PixelPtr + (x + X) + ((y + Y) * Display->GetWidth)) = Background; + } + FontPtr++; + } + break; + } + case Video::FontType::PCScreenFont2: + { + Video::FontInfo fInfo = CurrentFont->GetInfo(); + + int BytesPerLine = (fInfo.PSF2Font->Header->width + 7) / 8; + char *FontAddress = (char *)fInfo.StartAddress; + uint32_t FontHeaderSize = fInfo.PSF2Font->Header->headersize; + uint32_t FontCharSize = fInfo.PSF2Font->Header->charsize; + uint32_t FontLength = fInfo.PSF2Font->Header->length; + char *FontPtr = FontAddress + FontHeaderSize + (Char > 0 && (uint32_t)Char < FontLength ? Char : 0) * FontCharSize; + + uint32_t FontHdrWidth = fInfo.PSF2Font->Header->width; + uint32_t FontHdrHeight = fInfo.PSF2Font->Header->height; + + for (uint32_t Y = 0; Y < FontHdrHeight; Y++) + { + for (uint32_t X = 0; X < FontHdrWidth; X++) + { + void *FramebufferAddress = (void *)((uintptr_t)Display->GetBuffer + + ((y + Y) * Display->GetWidth + (x + X)) * + (Display->GetFramebufferStruct().BitsPerPixel / 8)); + + if ((*FontPtr & (0b10000000 >> (X % 8))) > 0) + *(uint32_t *)FramebufferAddress = Foreground; + else + *(uint32_t *)FramebufferAddress = Background; + } + FontPtr += BytesPerLine; + } + break; + } + default: + warn("Unsupported font type"); + break; + } + return Char; + } + + FontRenderer Renderer; + + void paint_callback(TerminalCell *cell, long x, long y) + { + if (cell->attr.Bright) + Renderer.Paint(x, y, cell->c, TermBrightColors[cell->attr.Foreground], TermColors[cell->attr.Background]); + else + Renderer.Paint(x, y, cell->c, TermColors[cell->attr.Foreground], TermColors[cell->attr.Background]); + } + + void cursor_callback(TerminalCursor *cur) + { + Renderer.Cursor = {cur->X, cur->Y}; + } + + VirtualTerminal *Terminals[16] = {nullptr}; + std::atomic CurrentTerminal = nullptr; + + bool SetTheme(std::string Theme) + { + FileNode *rn = fs->GetByPath("/etc/term", thisProcess->Info.RootNode); + if (rn == nullptr) + return false; + + kstat st{}; + rn->Stat(&st); + + char *sh = new char[st.Size]; + rn->Read(sh, st.Size, 0); + + ini_t *ini = ini_load(sh, NULL); + int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx; + const char *colors[8]; + + debug("Loading terminal theme: \"%s\"", Theme.c_str()); + themeSection = ini_find_section(ini, Theme.c_str(), NULL); + if (themeSection == INI_NOT_FOUND) + { + ini_destroy(ini); + delete[] sh; + return false; + } + + auto getColorComponent = [](const char *str, int &index) -> int + { + int value = 0; + while (str[index] >= '0' && str[index] <= '9') + { + value = value * 10 + (str[index] - '0'); + ++index; + } + return value; + }; + + auto parseColor = [getColorComponent](const char *colorStr) -> unsigned int + { + int index = 0; + int r = getColorComponent(colorStr, index); + if (colorStr[index] == ',') + ++index; + int g = getColorComponent(colorStr, index); + if (colorStr[index] == ',') + ++index; + int b = getColorComponent(colorStr, index); + return (r << 16) | (g << 8) | b; + }; + + c0 = ini_find_property(ini, themeSection, "color0", NULL); + c1 = ini_find_property(ini, themeSection, "color1", NULL); + c2 = ini_find_property(ini, themeSection, "color2", NULL); + c3 = ini_find_property(ini, themeSection, "color3", NULL); + c4 = ini_find_property(ini, themeSection, "color4", NULL); + c5 = ini_find_property(ini, themeSection, "color5", NULL); + c6 = ini_find_property(ini, themeSection, "color6", NULL); + c7 = ini_find_property(ini, themeSection, "color7", NULL); + + colors[0] = ini_property_value(ini, themeSection, c0); + colors[1] = ini_property_value(ini, themeSection, c1); + colors[2] = ini_property_value(ini, themeSection, c2); + colors[3] = ini_property_value(ini, themeSection, c3); + colors[4] = ini_property_value(ini, themeSection, c4); + colors[5] = ini_property_value(ini, themeSection, c5); + colors[6] = ini_property_value(ini, themeSection, c6); + colors[7] = ini_property_value(ini, themeSection, c7); + + colorsIdx = 0; + for (auto color : colors) + { + colorsIdx++; + if (color == 0) + continue; + + char *delimiterPos = strchr(color, ':'); + if (delimiterPos == NULL) + continue; + + char colorStr[20], colorBrightStr[20]; + strncpy(colorStr, color, delimiterPos - color); + colorStr[delimiterPos - color] = '\0'; + strcpy(colorBrightStr, delimiterPos + 1); + + TermColors[colorsIdx - 1] = parseColor(colorStr); + TermBrightColors[colorsIdx - 1] = parseColor(colorBrightStr); + } + + ini_destroy(ini); + delete[] sh; + return true; + } + +#ifdef DEBUG + void __test_themes() + { + printf("\x1b[H\x1b[2J"); + auto testTheme = [](const char *theme) + { + KernelConsole::SetTheme("vga"); + printf("== Theme: \"%s\" ==\n", theme); + KernelConsole::SetTheme(theme); + const char *txtColors[] = { + "30", "31", "32", "33", "34", "35", "36", "37", "39"}; + const char *bgColors[] = { + "40", "41", "42", "43", "44", "45", "46", "47", "49"}; + const int numTxtColors = sizeof(txtColors) / sizeof(txtColors[0]); + const int numBgColors = sizeof(bgColors) / sizeof(bgColors[0]); + + const char *msg = "H"; + for (int i = 0; i < numTxtColors; i++) + for (int j = 0; j < numBgColors; j++) + printf("\x1b[%sm\x1b[%sm%s\x1b[0m", txtColors[i], bgColors[j], msg); + + for (int i = 0; i < numTxtColors; i++) + for (int j = 0; j < numBgColors; j++) + printf("\x1b[1;%sm\x1b[1;%sm%s\x1b[0m", txtColors[i], bgColors[j], msg); + + KernelConsole::SetTheme("vga"); + printf("\n"); + }; + testTheme("vga"); + testTheme("breeze"); + testTheme("coolbreeze"); + testTheme("softlight"); + testTheme("calmsea"); + testTheme("warmember"); + // CPU::Stop(); + } +#endif + void EarlyInit() { - /* - - ICRNL - Map Carriage Return to New Line - - IXON - Enable XON/XOFF flow control + Renderer.CurrentFont = new Video::Font(&_binary_files_tamsyn_font_1_11_Tamsyn7x14r_psf_start, + &_binary_files_tamsyn_font_1_11_Tamsyn7x14r_psf_end, + Video::FontType::PCScreenFont2); - - OPOST - Enable output processing - - ONLCR - Map New Line to Carriage Return - New Line - - - CS8 - 8-bit characters - - CREAD - Enable receiver - - HUPCL - Hang up on last close - - - ECHO - Echo input characters - - ICANON - Enable canonical input (enable line editing) - */ - term.c_iflag = /*ICRNL |*/ IXON; - term.c_oflag = OPOST | ONLCR; - term.c_cflag = CS8 | CREAD | HUPCL; - term.c_lflag = ECHO | ICANON; - term.c_cc[VEOF] = 0x04; /* ^D */ - term.c_cc[VEOL] = 0x00; /* NUL */ - term.c_cc[VERASE] = 0x7f; /* DEL */ - term.c_cc[VINTR] = 0x03; /* ^C */ - term.c_cc[VKILL] = 0x15; /* ^U */ - term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */ - term.c_cc[VQUIT] = 0x1c; /* ^\ */ - term.c_cc[VSTART] = 0x11; /* ^Q */ - term.c_cc[VSTOP] = 0x13; /* ^S */ - term.c_cc[VSUSP] = 0x1a; /* ^Z */ - term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */ - term.c_cc[VWERASE] = 0x17; /* ^W */ + size_t Cols = Display->GetWidth / Renderer.CurrentFont->GetInfo().Width; + size_t Rows = Display->GetHeight / Renderer.CurrentFont->GetInfo().Height; + Terminals[0] = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, cursor_callback); + Terminals[0]->Clear(0, 0, Cols, Rows - 1); + CurrentTerminal.store(Terminals[0], std::memory_order_release); } void LateInit() { + new vfs::PTMXDevice; + + FileNode *rn = fs->GetByPath("/etc/term", thisProcess->Info.RootNode); + if (rn == nullptr) + return; + + kstat st{}; + rn->Stat(&st); + + char *sh = new char[st.Size]; + rn->Read(sh, st.Size, 0); + + ini_t *ini = ini_load(sh, NULL); + int general = ini_find_section(ini, "general", NULL); + int cursor = ini_find_section(ini, "cursor", NULL); + assert(general != INI_NOT_FOUND && cursor != INI_NOT_FOUND); + + int themeIndex = ini_find_property(ini, general, "theme", NULL); + assert(themeIndex != INI_NOT_FOUND); + + int cursorColor = ini_find_property(ini, cursor, "color", NULL); + int cursorBlink = ini_find_property(ini, cursor, "blink", NULL); + assert(cursorColor != INI_NOT_FOUND && cursorBlink != INI_NOT_FOUND); + + const char *colorThemeStr = ini_property_value(ini, general, themeIndex); + const char *cursorColorStr = ini_property_value(ini, cursor, cursorColor); + const char *cursorBlinkStr = ini_property_value(ini, cursor, cursorBlink); + debug("colorThemeStr=%s", colorThemeStr); + debug("cursorColorStr=%s", cursorColorStr); + debug("cursorBlinkStr=%s", cursorBlinkStr); + + auto getColorComponent = [](const char *str, int &index) -> int + { + int value = 0; + while (str[index] >= '0' && str[index] <= '9') + { + value = value * 10 + (str[index] - '0'); + ++index; + } + return value; + }; + + auto parseColor = [getColorComponent](const char *colorStr) -> unsigned int + { + int index = 0; + int r = getColorComponent(colorStr, index); + if (colorStr[index] == ',') + ++index; + int g = getColorComponent(colorStr, index); + if (colorStr[index] == ',') + ++index; + int b = getColorComponent(colorStr, index); + return (r << 16) | (g << 8) | b; + }; + + if (colorThemeStr != 0) + SetTheme(colorThemeStr); + + if (cursorBlinkStr != 0 && strncmp(cursorBlinkStr, "true", 4) == 0) + { + uint32_t blinkColor = 0xFFFFFF; + if (cursorColorStr != 0) + blinkColor = parseColor(cursorColorStr); + fixme("cursor blink with colors %X", blinkColor); + } + + ini_destroy(ini); + delete[] sh; + +#ifdef DEBUG + // __test_themes(); +#endif } } diff --git a/core/driver/daemon.cpp b/core/driver/daemon.cpp index b9bfab00..a9f7ca83 100644 --- a/core/driver/daemon.cpp +++ b/core/driver/daemon.cpp @@ -38,10 +38,12 @@ namespace Driver * maj = 0 * min: * 0 - - * 1 - /dev/null - * 2 - /dev/zero - * 3 - /dev/random - * 4 - /dev/mem + * 1 - /proc/self + * 2 - /dev/null + * 3 - /dev/zero + * 4 - /dev/random + * 5 - /dev/mem + * 6 - /dev/kcon * * maj = 1 * min: @@ -103,11 +105,11 @@ namespace Driver { switch (Node->GetMinor()) { - case 1: /* /dev/null */ + case 2: /* /dev/null */ { return 0; } - case 2: /* /dev/zero */ + case 3: /* /dev/zero */ { if (Size <= 0) return 0; @@ -115,7 +117,7 @@ namespace Driver memset(Buffer, 0, Size); return Size; } - case 3: /* /dev/random */ + case 4: /* /dev/random */ { if (Size <= 0) return 0; @@ -133,7 +135,12 @@ namespace Driver buf[i] = Random::rand64(); return Size; } - case 4: /* /dev/mem */ + case 5: /* /dev/mem */ + { + stub; + return 0; + } + case 6: /* /dev/kcon */ { stub; return 0; @@ -209,23 +216,31 @@ namespace Driver { switch (Node->GetMinor()) { - case 1: /* /dev/null */ + case 2: /* /dev/null */ { return Size; } - case 2: /* /dev/zero */ + case 3: /* /dev/zero */ { return Size; } - case 3: /* /dev/random */ + case 4: /* /dev/random */ { return Size; } - case 4: /* /dev/mem */ + case 5: /* /dev/mem */ { stub; return 0; } + case 6: /* /dev/kcon */ + { + char *buf = (char *)Buffer; + KernelConsole::VirtualTerminal *vt = KernelConsole::CurrentTerminal.load(); + for (size_t i = 0; i < Size; i++) + vt->Process(buf[i]); + return Size; + } default: return -ENOENT; }; @@ -552,6 +567,7 @@ namespace Driver dev->Device = fs->RegisterFileSystem(fsi, dev); dev->SetDevice(0, MinorID++); + MinorID++; /* 1 = /proc/self */ devNode = fs->Mount(fs->GetRoot(0), dev, "/dev"); _dev->Parent = devNode->Parent; @@ -613,6 +629,13 @@ namespace Driver S_IFCHR; createDevice(_dev, devNode, "mem", 0, MinorID++, mode); + /* c rw- r-- --- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | + + S_IFCHR; + createDevice(_dev, devNode, "kcon", 0, MinorID++, mode); + /* ------------------------------------------------------ */ MinorID = 0; diff --git a/core/driver/driver.cpp b/core/driver/driver.cpp index 37ad0ff5..cda5fea6 100644 --- a/core/driver/driver.cpp +++ b/core/driver/driver.cpp @@ -89,7 +89,7 @@ namespace Driver { if (Drivers.empty()) { - KPrint("\eE85230No drivers to load"); + KPrint("\x1b[1;31;41mNo drivers to load"); return; } diff --git a/core/panic/diag.cpp b/core/panic/diag.cpp index cf5c7e8f..d6cca65c 100644 --- a/core/panic/diag.cpp +++ b/core/panic/diag.cpp @@ -41,7 +41,6 @@ #include "keyboard.hpp" extern void ExPrint(const char *Format, ...); -extern Video::Font *CrashFont; extern void DisplayTopOverlay(); extern CPU::ExceptionFrame *ExFrame; @@ -75,7 +74,7 @@ nsa bool WriteDiagDataToNode(FileNode *node) uint8_t *buf = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(fileSize)); if (!buf) { - ExPrint("\eFF0000Failed to allocate memory for diagnostic data\n"); + ExPrint("\x1b[0;30;41mFailed to allocate memory for diagnostic data\x1b[0m\n"); Display->UpdateBuffer(); return false; } @@ -89,12 +88,12 @@ nsa bool WriteDiagDataToNode(FileNode *node) file->Data.KernelMemoryLength = uint32_t(kSize); memcpy(file->Data.KernelMemory, (void *)KStart, kSize); - ExPrint("\eFAFAFAWriting to %s\n", node->Path.c_str()); + ExPrint("Writing to %s\n", node->Path.c_str()); size_t w = node->Write(buf, fileSize, 0); if (w != fileSize) { debug("%d out of %d bytes written", w, fileSize); - ExPrint("\eFF0000Failed to write diagnostic data to file: %s\n", + ExPrint("\x1b[0;30;41mFailed to write diagnostic data to file: %s\x1b[0m\n", strerror((int)w)); Display->UpdateBuffer(); return false; @@ -108,7 +107,7 @@ nsa void DiagnosticDataCollection() Display->ClearBuffer(); DisplayTopOverlay(); - ExPrint("\n\eFAFAFAPlease wait while we collect some diagnostic information...\n"); + ExPrint("\nPlease wait while we collect some diagnostic information...\n"); ExPrint("This may take a while...\n"); mode_t mode = S_IRWXU | @@ -119,7 +118,7 @@ nsa void DiagnosticDataCollection() FileNode *panicDir = fs->ForceCreate(nullptr, "/var/panic", mode); if (!panicDir) { - ExPrint("\eFF0000Failed to create /var/panic\n"); + ExPrint("\x1b[0;30;41mFailed to create /var/panic\x1b[0m\n"); Display->UpdateBuffer(); return; } diff --git a/core/panic/handler.cpp b/core/panic/handler.cpp index ff09d7d7..75272501 100644 --- a/core/panic/handler.cpp +++ b/core/panic/handler.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ #include "../../kernel.h" +using namespace KernelConsole; + extern const char *x86ExceptionMnemonics[]; extern void DisplayCrashScreen(CPU::ExceptionFrame *); extern bool UserModeExceptionHandler(CPU::ExceptionFrame *); @@ -45,13 +48,43 @@ extern void DisplayStackSmashing(); extern void DisplayBufferOverflow(); extern void DisplayAssertionFailed(const char *, int, const char *); -Video::Font *CrashFont = nullptr; void *FbBeforePanic = nullptr; size_t FbPagesBeforePanic = 0; +FontRenderer CrashFontRenderer; + +int ExTermColors[] = { + [TerminalColor::BLACK] = 0x000000, + [TerminalColor::RED] = 0xAA0000, + [TerminalColor::GREEN] = 0x00AA00, + [TerminalColor::YELLOW] = 0xAA5500, + [TerminalColor::BLUE] = 0x0000AA, + [TerminalColor::MAGENTA] = 0xAA00AA, + [TerminalColor::CYAN] = 0x00AAAA, + [TerminalColor::GREY] = 0xAAAAAA, +}; + +int ExTermBrightColors[] = { + [TerminalColor::BLACK] = 0x858585, + [TerminalColor::RED] = 0xFF5555, + [TerminalColor::GREEN] = 0x55FF55, + [TerminalColor::YELLOW] = 0xFFFF55, + [TerminalColor::BLUE] = 0x5555FF, + [TerminalColor::MAGENTA] = 0xFF55FF, + [TerminalColor::CYAN] = 0x55FFFF, + [TerminalColor::GREY] = 0xFFFFFF, +}; + +void paint_callback(TerminalCell *cell, long x, long y) +{ + if (cell->attr.Bright) + CrashFontRenderer.Paint(x, y, cell->c, ExTermBrightColors[cell->attr.Foreground], ExTermColors[cell->attr.Background]); + else + CrashFontRenderer.Paint(x, y, cell->c, ExTermColors[cell->attr.Foreground], ExTermColors[cell->attr.Background]); +} nsa void __printfWrapper(char c, void *) { - Display->Print(c, CrashFont, true); + KernelConsole::Terminals[15]->Process(c); } nsa void ExPrint(const char *Format, ...) @@ -120,11 +153,17 @@ nsa void InitFont() } memcpy(FbBeforePanic, Display->GetBuffer, Display->GetSize); - if (CrashFont) - return; - CrashFont = new Video::Font(&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_start, - &_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_end, - Video::FontType::PCScreenFont2); + if (CrashFontRenderer.CurrentFont == nullptr) + CrashFontRenderer.CurrentFont = new Video::Font(&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_start, + &_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_end, + Video::FontType::PCScreenFont2); + + if (Terminals[15] == nullptr) + { + size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width; + size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height; + Terminals[15] = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr); + } } std::atomic UnrecoverableLock = false; @@ -137,7 +176,7 @@ nsa __noreturn void HandleUnrecoverableException(CPU::ExceptionFrame *Frame) for (uint32_t y = 0; y < Display->GetHeight; y++) Display->SetPixel(x, y, 0xFF250500); - Display->SetBufferCursor(0, 0); + ExPrint("\x1b[H"); } CPUData *core = GetCurrentCPU(); @@ -145,8 +184,8 @@ nsa __noreturn void HandleUnrecoverableException(CPU::ExceptionFrame *Frame) while (UnrecoverableLock.exchange(true, std::memory_order_acquire)) CPU::Pause(); - ExPrint("\eFFFFFF-----------------------------------------------\n"); - ExPrint("Unrecoverable exception %#lx on CPU %d\n", + ExPrint("\x1b[0m-----------------------------------------------\n"); + ExPrint("\x1b[30;41mUnrecoverable exception %#lx on CPU %d\n", Frame->InterruptNumber, core->ID); #if defined(a86) ExPrint("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx\n", @@ -191,7 +230,7 @@ nsa __noreturn void HandleUnrecoverableException(CPU::ExceptionFrame *Frame) nsa __noreturn void HandleExceptionInsideException(CPU::ExceptionFrame *Frame) { - ExPrint("\eFFFFFF-----------------------------------------------\n"); + ExPrint("\x1b[0m-----------------------------------------------\n"); ExPrint("Exception inside exception: %#lx at %#lx\n", Frame->InterruptNumber, #if defined(a64) @@ -282,14 +321,13 @@ nsa void HandleException(CPU::ExceptionFrame *Frame) { const char msg[] = "Entering in panic mode..."; size_t msgLen = strlen(msg); - size_t msgPixels = msgLen * CrashFont->GetInfo().Width; + size_t msgPixels = msgLen * CrashFontRenderer.CurrentFont->GetInfo().Width; uint32_t x = uint32_t((Display->GetWidth - msgPixels) / 2); - uint32_t y = uint32_t((Display->GetHeight - CrashFont->GetInfo().Height) / 2); - Display->SetBufferCursor(x, y); - Display->PrintString("\eFF2525"); - Display->PrintString(msg, CrashFont); - Display->SetBufferCursor(0, 0); - Display->UpdateBuffer(); + uint32_t y = uint32_t((Display->GetHeight - CrashFontRenderer.CurrentFont->GetInfo().Height) / 2); + x /= CrashFontRenderer.CurrentFont->GetInfo().Width; + y /= CrashFontRenderer.CurrentFont->GetInfo().Height; + printf("\x1b[2J\x1b[%d;%dH", y, x); + printf("\x1b[30;41m%s\x1b[0m\x1b[H", msg); } if (DriverManager) @@ -314,12 +352,16 @@ nsa void BaseBufferStackError(bool Stack) do it for us if we return. */ CPU::PageTable(KernelPageTable); - if (CrashFont == nullptr) + if (CrashFontRenderer.CurrentFont == nullptr) + CrashFontRenderer.CurrentFont = new Video::Font(&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_start, + &_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_end, + Video::FontType::PCScreenFont2); + + if (Terminals[15] == nullptr) { - /* Hope we won't crash here */ - CrashFont = new Video::Font(&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_start, - &_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_end, - Video::FontType::PCScreenFont2); + size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width; + size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height; + Terminals[15] = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr); } ExceptionLock.store(true, std::memory_order_release); diff --git a/core/panic/keyboard.cpp b/core/panic/keyboard.cpp index a3e1b2d9..3aecce86 100644 --- a/core/panic/keyboard.cpp +++ b/core/panic/keyboard.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -33,13 +34,16 @@ #include "../../kernel.h" -#define ERROR_COLOR "\eFF0000" -#define WARN_COLOR "\eFFAA00" -#define DEFAULT_COLOR "\e00FF00" +using namespace KernelConsole; + +#define ERROR_COLOR "\x1b[31m" +#define WARN_COLOR "\x1b[33m" +#define DEFAULT_COLOR "\x1b[0m" extern void ExPrint(const char *Format, ...); extern void ArrowInput(uint8_t key); extern void UserInput(char *Input); +extern FontRenderer CrashFontRenderer; const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y', @@ -142,16 +146,13 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ { #define WaitRead PS2Wait(true) #define WaitWrite PS2Wait(false) -#define SetMessageLocation \ - Display->SetBufferCursor(8, \ - Display->GetHeight - \ - Display->GetCurrentFont()->GetInfo().Height - 24) +#define SetMessageLocation \ + ExPrint("\x1b[%d;%dH", (Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width) - 1, 0); + CPU::Interrupts(CPU::Disable); /* Dots will be printed at the bottom of the screen as a progress bar. */ - Display->SetBufferCursor(8, - Display->GetHeight - - Display->GetCurrentFont()->GetInfo().Height - 8); + ExPrint("\x1b[%d;%dH", (Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width) - 2, 0); #if defined(a86) /* Disable port 1 & 2 */ @@ -164,7 +165,7 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ WaitWrite; outb(0x64, 0xA7); } - Display->Print('.'); + ExPrint("."); /* Flush */ { @@ -181,7 +182,7 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ } } - Display->Print('.'); + ExPrint("."); /* Test controller */ { /* Save config */ @@ -221,7 +222,7 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ WaitWrite; outb(0x60, cfg); } - Display->Print('.'); + ExPrint("."); /* Disable scanning; Enable port 1; Set default settings */ { @@ -235,7 +236,7 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ /* Set default settings */ outb(0x60, 0xF6); } - Display->Print('.'); + ExPrint("."); /* Test port 1 */ { @@ -264,7 +265,7 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ } } } - Display->Print('.'); + ExPrint("."); /* Configure the controller */ { @@ -283,7 +284,7 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ WaitWrite; outb(0x60, cfg); } - Display->Print('.'); + ExPrint("."); /* Enable port 1; Set scan code; Enable scanning */ { @@ -327,7 +328,7 @@ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */ /* Enable scanning */ outb(0x60, 0xF4); } - Display->Print('.'); + ExPrint("."); #endif // defined(a86) @@ -365,7 +366,8 @@ nsa void CrashKeyboardDriver::OnInterruptReceived(CPU::TrapFrame *Frame) { if (BackSpaceLimit > 0) { - Display->Print('\b'); + char keyBuf[5] = {'\b', '\x1b', '[', 'K', '\0'}; + ExPrint(keyBuf); backspace(UserInputBuffer); BackSpaceLimit--; } @@ -379,7 +381,8 @@ nsa void CrashKeyboardDriver::OnInterruptReceived(CPU::TrapFrame *Frame) else { append(UserInputBuffer, s_cst(char, key)); - Display->Print((char)key); + char keyBuf[2] = {(char)key, '\0'}; + ExPrint(keyBuf); BackSpaceLimit++; } Display->UpdateBuffer(); /* Update as we type. */ diff --git a/core/panic/ui.cpp b/core/panic/ui.cpp index f9380b78..e185cbbc 100644 --- a/core/panic/ui.cpp +++ b/core/panic/ui.cpp @@ -42,8 +42,8 @@ extern void ExPrint(const char *Format, ...); extern void DiagnosticDataCollection(); extern void InitFont(); +extern KernelConsole::FontRenderer CrashFontRenderer; -extern Video::Font *CrashFont; extern void *FbBeforePanic; struct StackFrame @@ -168,8 +168,7 @@ nsa char *TrimWhiteSpace(char *str) nsa void ExDumpData(void *Address, unsigned long Length) { - ExPrint("\eAAAAAA-------------------------------------------------------------------------\n"); - Display->UpdateBuffer(); + ExPrint("-------------------------------------------------------------------------\n"); unsigned char *AddressChar = (unsigned char *)Address; unsigned char Buffer[17]; unsigned long Iterate; @@ -178,11 +177,10 @@ nsa void ExDumpData(void *Address, unsigned long Length) if ((Iterate % 16) == 0) { if (Iterate != 0) - ExPrint(" \e8A78FF%s\eAABBCC\n", Buffer); - ExPrint(" \e9E9E9E%04x\eAABBCC ", Iterate); - Display->UpdateBuffer(); + ExPrint(" %s\n", Buffer); + ExPrint(" %04x ", Iterate); } - ExPrint(" \e4287f5%02x\eAABBCC", AddressChar[Iterate]); + ExPrint(" %02x", AddressChar[Iterate]); if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7E)) Buffer[Iterate % 16] = '.'; else @@ -193,65 +191,38 @@ nsa void ExDumpData(void *Address, unsigned long Length) while ((Iterate % 16) != 0) { ExPrint(" "); - Display->UpdateBuffer(); Iterate++; } - ExPrint(" \e8A78FF%s\eAAAAAA\n", Buffer); + ExPrint(" %s\n", Buffer); ExPrint("-------------------------------------------------------------------------\n\n."); - Display->UpdateBuffer(); } nsa void DisplayTopOverlay() { - Video::Font *f = Display->GetCurrentFont(); - Video::FontInfo fi = f->GetInfo(); - - for (uint32_t i = 0; i < Display->GetWidth; i++) - { - for (uint32_t j = 0; j < fi.Height + 8; j++) - { - // uint32_t grayValue = 0x505050 - (j * 0x020202); - // Display->SetPixel(i, j, grayValue); - Display->SetPixel(i, j, 0x202020); - } - } - - for (uint32_t i = 0; i < Display->GetWidth; i++) - Display->SetPixel(i, fi.Height + 8, 0x404040); - - Display->SetBufferCursor(8, (fi.Height + 8) / 6); - - /* This wouldn't have enough space for a 640x480 screen */ - // ExPrint("%sMAIN %sDETAILS %sSTACK %sPROCESS \eAAAAAA| ", - // ActiveScreen == 0 ? "\e00AAFF" : "\eAAAAAA", - // ActiveScreen == 1 ? "\e00AAFF" : "\eAAAAAA", - // ActiveScreen == 2 ? "\e00AAFF" : "\eAAAAAA", - // ActiveScreen == 3 ? "\e00AAFF" : "\eAAAAAA"); - - ExPrint("%s %s %s %s \eAAAAAA| ", - ActiveScreen == 0 ? "\eAAAAAA" + ExPrint("\x1b[H%s %s %s %s \x1b[0m| ", + ActiveScreen == 0 ? "\x1b[1;37m" "MAIN " - : "\e5A5A5A" + : "\x1b[0m" "M", - ActiveScreen == 1 ? "\eAAAAAA" + ActiveScreen == 1 ? "\x1b[1;37m" "DETAIL " - : "\e5A5A5A" + : "\x1b[0m" "D", - ActiveScreen == 2 ? "\eAAAAAA" + ActiveScreen == 2 ? "\x1b[1;37m" "STACK " - : "\e5A5A5A" + : "\x1b[0m" "S", - ActiveScreen == 3 ? "\eAAAAAA" + ActiveScreen == 3 ? "\x1b[1;37m" "PROCESS" - : "\e5A5A5A" + : "\x1b[0m" "P"); ExPrint("%s %s %s | ", KERNEL_NAME, KERNEL_ARCH, KERNEL_VERSION); ExPrint("%ld | ", TO_MiB(KernelAllocator.GetFreeMemory())); ExPrint("%s %s", CPU::Hypervisor(), CPU::Vendor()); - Display->SetBufferCursor(0, fi.Height + 10); + ExPrint("\x1b[3;1H"); /* https://imgflip.com/i/77slbl */ if ((Random::rand32() % 100) >= 98) @@ -320,23 +291,12 @@ nsa void DisplayTopOverlay() nsa void DisplayBottomOverlay() { - Video::Font *f = Display->GetCurrentFont(); - Video::FontInfo fi = f->GetInfo(); - - for (uint32_t i = 0; i < Display->GetWidth; i++) - for (uint32_t j = Display->GetHeight - fi.Height - 8; j < Display->GetHeight; j++) - Display->SetPixel(i, j, 0x202020); - - for (uint32_t i = 0; i < Display->GetWidth; i++) - Display->SetPixel(i, Display->GetHeight - fi.Height - 8, 0x404040); - - Display->SetBufferCursor(8, Display->GetHeight - fi.Height - 4); - ExPrint("\eAAAAAA> \eFAFAFA"); + ExPrint("\x1b[%d;%dH> \x1b[1;37m", (Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width) - 1, 1); } nsa void DisplayMainScreen(CPU::ExceptionFrame *Frame) { - ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n"); + ExPrint("\nWe're sorry, but the system has encountered a critical error and needs to restart.\n"); ExPrint("\nError: %s (%s 0x%x)\n", #if defined(a86) @@ -373,15 +333,15 @@ nsa void DisplayMainScreen(CPU::ExceptionFrame *Frame) ExPrint(" 2. Remove any newly installed hardware.\n"); ExPrint(" 3. Check for any available updates for your operating system.\n"); ExPrint(" 4. Uninstall any recently installed drivers or software.\n"); - ExPrint(" If none of the above steps resolve the issue, create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n"); + ExPrint(" If none of the above steps resolve the issue, create a new issue on https://github.com/Fennix-Project/Fennix for further assistance.\n"); ExPrint("\nUse command 'diag' to create a diagnostic report.\n"); } nsa void DisplayDetailsScreen(CPU::ExceptionFrame *Frame) { - ExPrint("\n\eFAFAFAException Frame:\n"); - ExPrint(" General Purpose Registers:\n\eAAAAAA"); + ExPrint("\nException Frame:\n"); + ExPrint(" General Purpose Registers:\n"); ExPrint(" RAX: %#lx RBX: %#lx RCX: %#lx RDX: %#lx\n", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx); ExPrint(" RSI: %#lx RDI: %#lx R8: %#lx R9: %#lx\n", @@ -390,28 +350,28 @@ nsa void DisplayDetailsScreen(CPU::ExceptionFrame *Frame) Frame->r10, Frame->r11, Frame->r12, Frame->r13); ExPrint(" R14: %#lx R15: %#lx\n", Frame->r14, Frame->r15); - ExPrint("\eFAFAFA Control Registers:\n\eAAAAAA"); + ExPrint(" Control Registers:\n"); ExPrint(" CR0: %#lx CR2: %#lx CR3: %#lx CR4: %#lx\n", Frame->cr0, Frame->cr2, Frame->cr3, Frame->cr4); ExPrint(" CR8: %#lx\n", Frame->cr8); - ExPrint("\eFAFAFA Segment Registers:\n\eAAAAAA"); + ExPrint(" Segment Registers:\n"); ExPrint(" CS: %#lx SS: %#lx DS: %#lx ES: %#lx FS: %#lx GS: %#lx\n", Frame->cs, Frame->ss, Frame->ds, Frame->es, Frame->fs, Frame->gs); - ExPrint("\eFAFAFA Debug Registers:\n\eAAAAAA"); + ExPrint(" Debug Registers:\n"); ExPrint(" DR0: %#lx DR1: %#lx DR2: %#lx DR3: %#lx\n", Frame->dr0, Frame->dr1, Frame->dr2, Frame->dr3); ExPrint(" DR6: %#lx DR7: %#lx\n", Frame->dr6, Frame->dr7); - ExPrint("\eFAFAFA Other:\n\eAAAAAA"); + ExPrint(" Other:\n"); ExPrint(" INT: %#lx ERR: %#lx RIP: %#lx RFLAGS: %#lx\n", Frame->InterruptNumber, Frame->ErrorCode, Frame->rip, Frame->rflags.raw); ExPrint(" RSP: %#lx RBP: %#lx\n", Frame->rsp, Frame->rbp); - ExPrint("\eFAFAFAException Details:\n"); + ExPrint("Exception Details:\n"); switch (Frame->InterruptNumber) { case CPU::x86::PageFault: @@ -477,7 +437,7 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) sf = (struct StackFrame *)Frame->ebp; #endif - ExPrint("\n\eFAFAFAStack trace (%#lx):\n", sf); + ExPrint("\nStack trace (%#lx):\n", sf); if (!vmm.Check(sf)) { @@ -487,7 +447,7 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) sf = (struct StackFrame *)ptr; else { - ExPrint("\eFF0000< No stack trace available. >\n"); + ExPrint("\x1b[31m< No stack trace available. >\x1b[0m\n"); return; } } @@ -503,8 +463,8 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) fIP = Frame->pc; #endif - ExPrint("\eAAAAAA%p", (void *)fIP); - ExPrint("\e5A5A5A in "); + ExPrint("%p", (void *)fIP); + ExPrint(" in "); if ((fIP >= (uintptr_t)&_kernel_start && fIP <= (uintptr_t)&_kernel_end)) { @@ -513,15 +473,15 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) if (offset < 0) offset = -offset; - ExPrint("\eFAFAFA%s\e5A5A5A+%#lx \eFFAAAA<- Exception\n", + ExPrint("%s+%#lx \x1b[31m<- Exception\x1b[0m\n", sym, offset); } else - ExPrint("\eFF5555??? \eFFAAAA<- Exception\n"); + ExPrint("??? \x1b[31m<- Exception\x1b[0m\n"); if (!sf || !sf->ip || !sf->bp) { - ExPrint("\n\eFF0000< No stack trace available. >\n"); + ExPrint("\n\x1b[31m< No stack trace available. >\x1b[0m\n"); return; } @@ -530,8 +490,8 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) if (!sf->ip) break; - ExPrint("\eAAAAAA%p", (void *)sf->ip); - ExPrint("\e5A5A5A in "); + ExPrint("%p", (void *)sf->ip); + ExPrint(" in "); if ((sf->ip >= (uintptr_t)&_kernel_start && sf->ip <= (uintptr_t)&_kernel_end)) { @@ -540,10 +500,10 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) if (offset < 0) offset = -offset; - ExPrint("\eFAFAFA%s\e5A5A5A+%#lx\n", sym, offset); + ExPrint("%s+%#lx\n", sym, offset); } else - ExPrint("\eFF5555???\n"); + ExPrint("???\n"); if (!vmm.Check(sf->bp)) return; @@ -554,17 +514,17 @@ nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame) nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = true) { const char *StatusColor[] = { - "FF0000", // Unknown - "AAFF00", // Ready - "00AA00", // Running - "FFAA00", // Sleeping - "FFAA00", // Blocked - "FFAA00", // Stopped - "FFAA00", // Waiting + "31m", // Unknown + "1;33m", // Ready + "32m", // Running + "1;33m", // Sleeping + "1;33m", // Blocked + "1;33m", // Stopped + "1;33m", // Waiting - "FF00FF", // Core dump - "FF0088", // Zombie - "FF0000", // Terminated + "35m", // Core dump + "1;31m", // Zombie + "31m", // Terminated }; const char *StatusString[] = { @@ -583,7 +543,7 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru if (!TaskManager) { - ExPrint("\eFF5555Tasking is not initialized\n"); + ExPrint("Tasking is not initialized\n"); return; } @@ -593,7 +553,7 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru std::vector Plist = TaskManager->GetProcessList(); - ExPrint("\n\eFAFAFAProcess list (%ld):\n", Plist.size()); + ExPrint("\nProcess list (%ld):\n", Plist.size()); bool pRdy = false; bool showNote = false; /* FIXME: This is slow */ @@ -620,9 +580,9 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru } } - ExPrint("\eAAAAAA-> \eFAFAFA%.*s%s\e8A8A8A(%ld) \e%s%s \e8A8A8A[exe: %s]\n", + ExPrint("-> %.*s%s(%ld) \x1b[%s%s\x1b[0m [exe: %s]\n", textLimit, Process->Name, - strlen(Process->Name) > textLimit ? "\e8A8A8A..." : "", + strlen(Process->Name) > textLimit ? "..." : "", Process->ID, StatusColor[Process->State.load()], StatusString[Process->State.load()], Process->Executable @@ -641,22 +601,24 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru continue; } - ExPrint("\eAAAAAA -> \eFAFAFA%.*s%s\e8A8A8A(%ld) \e%s%s\n", + ExPrint(" -> %.*s%s(%ld) \x1b[%s%s\x1b[0m\n", textLimit, Thread->Name, - strlen(Thread->Name) > textLimit ? "\e8A8A8A..." : "", + strlen(Thread->Name) > textLimit ? "..." : "", Thread->ID, StatusColor[Thread->State.load()], StatusString[Thread->State.load()]); } if (tRdy) - ExPrint("\eAAAAAA%s -> \e8A8A8A...\n"); + ExPrint(" -> ...\n"); } if (pRdy) - ExPrint("\eAAAAAA-> \e8A8A8A...\n"); + ExPrint("-> ...\n"); if (showNote) - ExPrint("\e5A5A5ANote: Some processes may not be displayed.\n"); + ExPrint("Note: Some processes may not be displayed.\n"); } +void UserInput(char *Input); +void ArrowInput(uint8_t key); CPU::ExceptionFrame *ExFrame; nsa void DisplayCrashScreen(CPU::ExceptionFrame *Frame) { @@ -668,11 +630,10 @@ nsa void DisplayCrashScreen(CPU::ExceptionFrame *Frame) // memcpy(BufferBeforeUpdate, Display->GetBuffer, Display->GetSize); Display->ClearBuffer(); + ExPrint("\x1b[2J\x1b[H"); if (Config.InterruptsOnCrash == false) { - Display->SetBufferCursor(0, 0); DisplayMainScreen(Frame); - Display->UpdateBuffer(); CPU::Stop(); } @@ -680,21 +641,122 @@ nsa void DisplayCrashScreen(CPU::ExceptionFrame *Frame) DisplayMainScreen(Frame); - Display->UpdateBuffer(); new CrashKeyboardDriver; DisplayBottomOverlay(); - Display->UpdateBuffer(); - CPU::Halt(true); + // CPU::Halt(true); + +#ifdef DEBUG + static int once = 0; + static uint8_t com4 = 0xFF; + if (!once++) + com4 = inb(0x2E8); + if (com4 == 0xFF) + CPU::Halt(true); + + char UserInputBuffer[256]{'\0'}; + int BackSpaceLimit = 0; + + while (true) + { + while ((inb(0x2E8 + 5) & 1) == 0) + CPU::Pause(); + char key = inb(0x2E8); + // debug("key: %d", key); + + if (key == '\x7f') /* Backspace (DEL) */ + { + if (BackSpaceLimit <= 0) + continue; + + char keyBuf[5] = {'\b', '\x1b', '[', 'K', '\0'}; + ExPrint(keyBuf); + backspace(UserInputBuffer); + BackSpaceLimit--; + continue; + } + else if (key == '\x0d') /* Enter (CR) */ + { + UserInput(UserInputBuffer); + BackSpaceLimit = 0; + UserInputBuffer[0] = '\0'; + continue; + } + else if (key == '\x1b') /* Escape */ + { + char tmp[16]{'\0'}; + append(tmp, key); + + while ((inb(0x2E8 + 5) & 1) == 0) + CPU::Pause(); + char key = inb(0x2E8); + append(tmp, key); + + if (key == '[') + { + // 27 91 + // < 68 + // > 67 + // down 66 + // up 65 + while ((inb(0x2E8 + 5) & 1) == 0) + CPU::Pause(); + key = inb(0x2E8); + append(tmp, key); + switch (key) + { + case 'A': + key = KEY_D_UP; + break; + case 'B': + key = KEY_D_DOWN; + break; + case 'C': + key = KEY_D_RIGHT; + break; + case 'D': + key = KEY_D_LEFT; + break; + default: + { + for (size_t i = 0; i < strlen(tmp); i++) + { + if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit) + continue; + + append(UserInputBuffer, tmp[i]); + BackSpaceLimit++; + char keyBuf[2] = {(char)tmp[i], '\0'}; + ExPrint(keyBuf); + } + continue; + } + } + + ArrowInput(key); + continue; + } + } + + if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit) + continue; + + append(UserInputBuffer, key); + BackSpaceLimit++; + char keyBuf[2] = {(char)key, '\0'}; + ExPrint(keyBuf); + } +#endif } nsa void DisplayStackSmashing() { InitFont(); + ExPrint("\x1b[2J\x1b[H"); Display->ClearBuffer(); DisplayTopOverlay(); - ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n"); + ExPrint("\nWe're sorry, but the system has encountered a critical error and needs to restart.\n"); ExPrint("\nError: Stack Smashing In Kernel Mode\n"); CPUData *core = GetCurrentCPU(); @@ -708,9 +770,7 @@ nsa void DisplayStackSmashing() ExPrint("\nWhat to do:\n"); ExPrint(" This is a kernel bug.\n"); - ExPrint(" Please create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n"); - - Display->UpdateBuffer(); + ExPrint(" Please create a new issue on https://github.com/Fennix-Project/Fennix for further assistance.\n"); /* TODO: Add additional info */ } @@ -718,10 +778,11 @@ nsa void DisplayStackSmashing() nsa void DisplayBufferOverflow() { InitFont(); + ExPrint("\x1b[2J\x1b[H"); Display->ClearBuffer(); DisplayTopOverlay(); - ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n"); + ExPrint("\nWe're sorry, but the system has encountered a critical error and needs to restart.\n"); ExPrint("\nError: Buffer Overflow In Kernel Mode\n"); CPUData *core = GetCurrentCPU(); @@ -735,9 +796,7 @@ nsa void DisplayBufferOverflow() ExPrint("\nWhat to do:\n"); ExPrint(" This is a kernel bug.\n"); - ExPrint(" Please create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n"); - - Display->UpdateBuffer(); + ExPrint(" Please create a new issue on https://github.com/Fennix-Project/Fennix for further assistance.\n"); /* TODO: Add additional info */ } @@ -745,10 +804,11 @@ nsa void DisplayBufferOverflow() nsa void DisplayAssertionFailed(const char *File, int Line, const char *Expression) { InitFont(); + ExPrint("\x1b[2J\x1b[H"); Display->ClearBuffer(); DisplayTopOverlay(); - ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n"); + ExPrint("\nWe're sorry, but the system has encountered a critical error and needs to restart.\n"); ExPrint("\nError: Assertion Failed\n"); ExPrint("In file \"%s\" at line %d, \"%s\" failed\n", File, Line, Expression); @@ -764,7 +824,7 @@ nsa void DisplayAssertionFailed(const char *File, int Line, const char *Expressi ExPrint("\nWhat to do:\n"); ExPrint(" This is a kernel bug.\n"); - ExPrint(" Please create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n"); + ExPrint(" Please create a new issue on https://github.com/Fennix-Project/Fennix for further assistance.\n"); CPU::ExceptionFrame ef; // Fill only the necessary fields @@ -789,7 +849,6 @@ nsa void DisplayAssertionFailed(const char *File, int Line, const char *Expressi ef.ebp = ef.esp = (uint32_t)stk; #endif DisplayStackScreen(&ef); - Display->UpdateBuffer(); /* TODO: Add additional info */ } @@ -817,6 +876,7 @@ nsa void ArrowInput(uint8_t key) } Display->ClearBuffer(); + ExPrint("\x1b[2J"); DisplayTopOverlay(); switch (ActiveScreen) @@ -838,31 +898,31 @@ nsa void ArrowInput(uint8_t key) } DisplayBottomOverlay(); - Display->UpdateBuffer(); } nsa void UserInput(char *Input) { debug("User input: %s", Input); Display->ClearBuffer(); + ExPrint("\x1b[2J"); DisplayTopOverlay(); if (strcmp(Input, "help") == 0) { ExPrint("Commands:\n"); - ExPrint("\eAAAAAA help - Display this help message.\n"); - ExPrint("\eCACACA clear - Clear the screen.\n"); - ExPrint("\eAAAAAA exit - Shutdown the device.\n"); - ExPrint("\eCACACA reboot - Reboot the device.\n"); - ExPrint("\eAAAAAA bitmap - Display the kernel's bitmap.\n"); - ExPrint("\eCACACA mem - Display memory information.\n"); - ExPrint("\eAAAAAA dump [addr] [len] - Dump [len] bytes from [addr].\n"); - ExPrint("\eCACACA diag - Collect diagnostic information.\n"); - ExPrint("\eAAAAAA screen - Display the final output prior to system panic.\n"); + ExPrint("\x1b[1;37m help - Display this help message.\n"); + ExPrint("\x1b[0m clear - Clear the screen.\n"); + ExPrint("\x1b[1;37m exit - Shutdown the device.\n"); + ExPrint("\x1b[0m reboot - Reboot the device.\n"); + ExPrint("\x1b[1;37m bitmap - Display the kernel's bitmap.\n"); + ExPrint("\x1b[0m mem - Display memory information.\n"); + ExPrint("\x1b[1;37m dump [addr] [len] - Dump [len] bytes from [addr].\n"); + ExPrint("\x1b[0m diag - Collect diagnostic information.\n"); + ExPrint("\x1b[1;37m screen - Display the final output prior to system panic.\n"); } else if (strcmp(Input, "clear") == 0) { - Display->ClearBuffer(); + ExPrint("\x1b[2J"); DisplayTopOverlay(); } else if (strcmp(Input, "exit") == 0) @@ -871,14 +931,15 @@ nsa void UserInput(char *Input) const char msg[] = "Shutting down..."; size_t msgLen = strlen(msg); - size_t msgPixels = msgLen * CrashFont->GetInfo().Width; + size_t msgPixels = msgLen * CrashFontRenderer.CurrentFont->GetInfo().Width; uint32_t x = uint32_t((Display->GetWidth - msgPixels) / 2); - uint32_t y = uint32_t((Display->GetHeight - CrashFont->GetInfo().Height) / 2); - Display->SetBufferCursor(x, y); - Display->PrintString("\eAAAAAA"); - Display->PrintString(msg, CrashFont); + uint32_t y = uint32_t((Display->GetHeight - CrashFontRenderer.CurrentFont->GetInfo().Height) / 2); + x /= CrashFontRenderer.CurrentFont->GetInfo().Width; + y /= CrashFontRenderer.CurrentFont->GetInfo().Height; + ExPrint("\x1b[2J"); + ExPrint("\x1b[%d;%dH", y, x); + ExPrint("\x1b[30;41m%s\x1b[0m\x1b[H", msg); - Display->UpdateBuffer(); PowerManager->Shutdown(); CPU::Stop(); } @@ -888,42 +949,37 @@ nsa void UserInput(char *Input) const char msg[] = "Rebooting..."; size_t msgLen = strlen(msg); - size_t msgPixels = msgLen * CrashFont->GetInfo().Width; + size_t msgPixels = msgLen * CrashFontRenderer.CurrentFont->GetInfo().Width; uint32_t x = uint32_t((Display->GetWidth - msgPixels) / 2); - uint32_t y = uint32_t((Display->GetHeight - CrashFont->GetInfo().Height) / 2); - Display->SetBufferCursor(x, y); - Display->PrintString("\eAAAAAA"); - Display->PrintString(msg, CrashFont); + uint32_t y = uint32_t((Display->GetHeight - CrashFontRenderer.CurrentFont->GetInfo().Height) / 2); + x /= CrashFontRenderer.CurrentFont->GetInfo().Width; + y /= CrashFontRenderer.CurrentFont->GetInfo().Height; + ExPrint("\x1b[2J"); + ExPrint("\x1b[%d;%dH", y, x); + ExPrint("\x1b[30;41m%s\x1b[0m\x1b[H", msg); - Display->UpdateBuffer(); PowerManager->Reboot(); CPU::Stop(); } else if (strncmp(Input, "bitmap", 6) == 0) { Bitmap bm = KernelAllocator.GetPageBitmap(); - Video::Font *oldFont = CrashFont; - CrashFont = Display->GetDefaultFont(); - ExPrint("\n\eAAAAAA[0%%] %08ld: ", 0); + ExPrint("\n[0%%] %08ld: ", 0); for (size_t i = 0; i < bm.Size; i++) { if (bm.Get(i)) - Display->PrintString("\eFF0000"); + ExPrint("\x1b[31m1\x1b[0m"); else - Display->PrintString("\e00FF00"); - Display->Print('0'); + ExPrint("\x1b[32m0\x1b[0m"); if (i % 128 == 127) { short Percentage = s_cst(short, (i * 100) / bm.Size); - ExPrint("\n\eAAAAAA[%03ld%%] %08ld: ", Percentage, i); - Display->UpdateBuffer(); + ExPrint("\n[%03ld%%] %08ld: ", Percentage, i); } } - ExPrint("\n\eAAAAAA--- END OF BITMAP ---\nBitmap size: %ld\n\n.", bm.Size); + ExPrint("\n--- END OF BITMAP ---\nBitmap size: %ld\n\n.", bm.Size); DisplayTopOverlay(); - Display->UpdateBuffer(); - CrashFont = oldFont; } else if (strcmp(Input, "mem") == 0) { @@ -932,17 +988,17 @@ nsa void UserInput(char *Input) uint64_t Free = KernelAllocator.GetFreeMemory(); uint64_t Reserved = KernelAllocator.GetReservedMemory(); - ExPrint("\e22AA44Total: %ld bytes\n\eFF0000Used: %ld bytes\n\e00FF00Free: %ld bytes\n\eFF00FFReserved: %ld bytes\n", Total, Used, Free, Reserved); + ExPrint("\x1b[1;32mTotal: %ld bytes\n\x1b[1;31mUsed: %ld bytes\n\x1b[1;32mFree: %ld bytes\n\x1b[1;35mReserved: %ld bytes\n", Total, Used, Free, Reserved); int Progress = s_cst(int, (Used * 100) / Total); int ReservedProgress = s_cst(int, (Reserved * 100) / Total); - ExPrint("\e22AA44%3d%% \eCCCCCC[", Progress); + ExPrint("\x1b[1;32m%3d%% \x1b[0m[", Progress); for (int i = 0; i < Progress; i++) - ExPrint("\eFF0000|"); + ExPrint("\x1b[1;31m|"); for (int i = 0; i < 100 - Progress; i++) - ExPrint("\e00FF00|"); + ExPrint("\x1b[1;32m|"); for (int i = 0; i < ReservedProgress; i++) - ExPrint("\eFF00FF|"); - ExPrint("\eCCCCCC]\eAAAAAA\n"); + ExPrint("\x1b[1;35m|"); + ExPrint("\x1b[0m]\n"); } else if (strncmp(Input, "dump", 4) == 0) { @@ -951,7 +1007,7 @@ nsa void UserInput(char *Input) char *len = strtok(NULL, " "); if (addr == NULL || len == NULL) { - ExPrint("\eFF0000Invalid arguments\n"); + ExPrint("\x1b[31mInvalid arguments\n"); goto End; } @@ -968,7 +1024,7 @@ nsa void UserInput(char *Input) { if (!vmm.Check((void *)adr)) { - ExPrint("\eFFA500Address %#lx is not mapped\n", adr); + ExPrint("\x1b[31mAddress %#lx is not mapped\n", adr); IsRangeValid = false; } } @@ -977,11 +1033,7 @@ nsa void UserInput(char *Input) if (IsRangeValid) { debug("Dumping %ld bytes from %#lx\n", Length, Address); - - Video::Font *oldFont = CrashFont; - CrashFont = Display->GetDefaultFont(); ExDumpData((void *)Address, (unsigned long)Length); - CrashFont = oldFont; } } else if (strcmp(Input, "diag") == 0) @@ -992,11 +1044,10 @@ nsa void UserInput(char *Input) { if (unlikely(FbBeforePanic == nullptr)) { - ExPrint("\eFF0000No screen data available\n"); + ExPrint("No screen data available\n"); goto End; } memcpy(Display->GetBuffer, FbBeforePanic, Display->GetSize); - Display->UpdateBuffer(); return; } #ifdef DEBUG @@ -1018,5 +1069,4 @@ nsa void UserInput(char *Input) End: DisplayBottomOverlay(); - Display->UpdateBuffer(); } diff --git a/core/time/timer.cpp b/core/time/timer.cpp index 36661804..abac6347 100644 --- a/core/time/timer.cpp +++ b/core/time/timer.cpp @@ -156,11 +156,11 @@ namespace Time hpet = new HighPrecisionEventTimer(((ACPI::ACPI *)acpi)->HPET); ActiveTimer = HPET; SupportedTimers |= HPET; - KPrint("\e11FF11HPET found"); + KPrint("HPET found"); } else { - KPrint("\eFF2200HPET not found"); + KPrint("\x1b[33mHPET not found"); } /* TODO: ACPI check */ @@ -168,7 +168,7 @@ namespace Time } else { - KPrint("\eFF2200ACPI not found"); + KPrint("\x1b[33mACPI not found"); } bool TSCInvariant = false; @@ -191,10 +191,10 @@ namespace Time tsc = new TimeStampCounter; // FIXME: ActiveTimer = TSC; SupportedTimers |= TSC; - KPrint("\e11FF11Invariant TSC found"); + KPrint("Invariant TSC found"); } else - KPrint("\eFF2200TSC is not invariant"); + KPrint("\x1b[33mTSC is not invariant"); #endif } diff --git a/core/video/display.cpp b/core/video/display.cpp index 9e88566a..881587f7 100644 --- a/core/video/display.cpp +++ b/core/video/display.cpp @@ -24,8 +24,6 @@ NewLock(PrintLock); namespace Video { - Font *Display::GetCurrentFont() { return CurrentFont; } - void Display::SetCurrentFont(Font *Font) { CurrentFont = Font; } uint16_t Display::GetBitsPerPixel() { return this->framebuffer.BitsPerPixel; } size_t Display::GetPitch() { return this->framebuffer.Pitch; } @@ -83,223 +81,6 @@ namespace Video } } - void Display::Scroll(int Lines) - { - if (this->DoNotScroll) - return; - - if (Lines == 0) - return; - - if (Lines > 0) - { - uint32_t LineSize = this->Width * (this->framebuffer.BitsPerPixel / 8); - uint32_t BytesToMove = LineSize * Lines * this->CurrentFont->GetInfo().Height; - size_t BytesToClear = this->Size - BytesToMove; - memmove(this->Buffer, (uint8_t *)this->Buffer + BytesToMove, BytesToClear); - memset((uint8_t *)this->Buffer + BytesToClear, 0, BytesToMove); - - // memset(this->DirtyMap.data(), true, this->DirtyMap.size()); - } - } - - __no_sanitize("undefined") char Display::Print(char Char, - Video::Font *_Font, - bool WriteToUART, - bool IgnoreSpecialChars) - { - // SmartLock(PrintLock); - - if (this->ColorIteration) - { - // RRGGBB - if (Char >= '0' && Char <= '9') - this->Color = (this->Color << 4) | (Char - '0'); - else if (Char >= 'a' && Char <= 'f') - this->Color = (this->Color << 4) | (Char - 'a' + 10); - else if (Char >= 'A' && Char <= 'F') - this->Color = (this->Color << 4) | (Char - 'A' + 10); - else - this->Color = 0xFFFFFF; - this->ColorPickerIteration++; - if (this->ColorPickerIteration == 6) - { - this->ColorPickerIteration = 0; - this->ColorIteration = false; - } - return Char; - } - - if (WriteToUART && Char != '\e') - UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(Char); - - if (_Font == nullptr) - _Font = this->DefaultFont; - this->CurrentFont = _Font; - uint32_t FontHeight; - - if (IgnoreSpecialChars) - goto IgnoreSpecialChars; - - switch (Char) - { - case '\e': - { - this->ColorIteration = true; - return Char; - } - case '\b': - { - switch (_Font->GetInfo().Type) - { - case FontType::PCScreenFont1: - { - fixme("PCScreenFont1"); - break; - } - case FontType::PCScreenFont2: - { - uint32_t fonthdrWidth = _Font->GetInfo().PSF2Font->Header->width; - uint32_t fonthdrHeight = _Font->GetInfo().PSF2Font->Header->height; - - for (unsigned long Y = this->CursorY; Y < this->CursorY + fonthdrHeight; Y++) - for (unsigned long X = this->CursorX - fonthdrWidth; X < this->CursorX; X++) - *(uint32_t *)((uintptr_t)this->Buffer + - (Y * this->Width + X) * (this->framebuffer.BitsPerPixel / 8)) = 0; - - // for (size_t i = 0; i < 9; ++i) - // { - // size_t row = (CursorY / RegionHeight) + (i / 3) - 1; - // size_t col = (CursorX / RegionWidth) + (i % 3) - 1; - // if (row < Height / RegionHeight && col < Width / RegionWidth) - // MarkRegionDirty(row, col); - // } - break; - } - default: - warn("Unsupported font type"); - break; - } - - if (this->CursorX > 0) - this->CursorX -= this->GetCurrentFont()->GetInfo().Width; - - return Char; - } - case '\t': - { - this->CursorX = (this->CursorX + 8) & ~(8 - 1); - return Char; - } - case '\r': - { - this->CursorX = 0; - return Char; - } - case '\n': - { - this->CursorX = 0; - this->CursorY += this->GetCurrentFont()->GetInfo().Height; - return Char; - } - default: - break; - } - - IgnoreSpecialChars: - FontHeight = this->GetCurrentFont()->GetInfo().Height; - - if (this->CursorX + this->GetCurrentFont()->GetInfo().Width >= this->Width) - { - this->CursorX = 0; - this->CursorY += FontHeight; - } - - if (this->CursorY + FontHeight >= this->Height) - { - if (!this->DoNotScroll) - { - this->CursorY -= FontHeight; - this->Scroll(1); - } - } - - switch (_Font->GetInfo().Type) - { - case FontType::PCScreenFont1: - { - uint32_t *PixelPtr = (uint32_t *)this->Buffer; - char *FontPtr = (char *)_Font->GetInfo().PSF1Font->GlyphBuffer + (Char * _Font->GetInfo().PSF1Font->Header->charsize); - for (uint64_t Y = this->CursorY; Y < this->CursorY + 16; Y++) - { - for (uint64_t X = this->CursorX; X < this->CursorX + 8; X++) - if ((*FontPtr & (0b10000000 >> (X - this->CursorX))) > 0) - *(unsigned int *)(PixelPtr + X + (Y * this->Width)) = this->Color; - FontPtr++; - } - this->CursorX += 8; - - break; - } - case FontType::PCScreenFont2: - { - // if (_Font->PSF2Font->GlyphBuffer == (uint16_t *)0x01) // HAS UNICODE TABLE - // Char = _Font->PSF2Font->GlyphBuffer[Char]; - - FontInfo fInfo = _Font->GetInfo(); - - int BytesPerLine = (fInfo.PSF2Font->Header->width + 7) / 8; - char *FontAddress = (char *)fInfo.StartAddress; - uint32_t FontHeaderSize = fInfo.PSF2Font->Header->headersize; - uint32_t FontCharSize = fInfo.PSF2Font->Header->charsize; - uint32_t FontLength = fInfo.PSF2Font->Header->length; - char *FontPtr = FontAddress + FontHeaderSize + (Char > 0 && (uint32_t)Char < FontLength ? Char : 0) * FontCharSize; - - uint32_t FontHdrWidth = fInfo.PSF2Font->Header->width; - uint32_t FontHdrHeight = fInfo.PSF2Font->Header->height; - - for (size_t Y = this->CursorY; Y < this->CursorY + FontHdrHeight; Y++) - { - for (size_t X = this->CursorX; X < this->CursorX + FontHdrWidth; X++) - { - if ((*FontPtr & (0b10000000 >> (X - this->CursorX))) > 0) - { - void *FramebufferAddress = (void *)((uintptr_t)this->Buffer + - (Y * this->Width + X) * - (this->framebuffer.BitsPerPixel / 8)); - *(uint32_t *)FramebufferAddress = this->Color; - } - } - FontPtr += BytesPerLine; - } - this->CursorX += FontHdrWidth; - break; - } - default: - warn("Unsupported font type"); - break; - } - - // // MarkRegionDirty(CursorY / RegionHeight, CursorX / RegionWidth); - // for (size_t i = 0; i < 9; ++i) - // { - // size_t row = (CursorY / RegionHeight) + (i / 3) - 1; - // size_t col = (CursorX / RegionWidth) + (i % 3) - 1; - // if (row < Height / RegionHeight && col < Width / RegionWidth) - // MarkRegionDirty(row, col); - // } - return Char; - } - - void Display::PrintString(const char *String, - Video::Font *Font, - bool WriteToUART, - bool IgnoreSpecialChars) - { - for (size_t i = 0; String[i] != '\0'; ++i) - Print(String[i], Font, WriteToUART, IgnoreSpecialChars); - } - void Display::UpdateBuffer() { if (!DirectWrite) @@ -367,7 +148,6 @@ namespace Video } Display::Display(BootInfo::FramebufferInfo Info, - bool LoadDefaultFont, bool _DirectWrite) : framebuffer(Info), DirectWrite(_DirectWrite) { @@ -380,16 +160,6 @@ namespace Video Buffer = KernelAllocator.RequestPages(TO_PAGES(Size)); // DirtyMap.resize((Width / RegionWidth) * (Height / RegionHeight), false); - - if (!LoadDefaultFont) - return; - this->DefaultFont = new Font(&_binary_files_tamsyn_font_1_11_Tamsyn7x14r_psf_start, &_binary_files_tamsyn_font_1_11_Tamsyn7x14r_psf_end, FontType::PCScreenFont2); -#ifdef DEBUG - FontInfo fInfo = this->DefaultFont->GetInfo(); - debug("Font loaded: %dx%d %s", - fInfo.Width, fInfo.Height, - fInfo.Type == FontType::PCScreenFont1 ? "PSF1" : "PSF2"); -#endif } Display::~Display() {} diff --git a/core/vt.cpp b/core/vt.cpp new file mode 100644 index 00000000..39568d46 --- /dev/null +++ b/core/vt.cpp @@ -0,0 +1,499 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include +#include + +#include "../kernel.h" + +namespace KernelConsole +{ + void VirtualTerminal::Clear(unsigned short StartX, unsigned short StartY, unsigned short EndX, unsigned short EndY) + { + assert(this->PaintCB != nullptr); + for (long i = StartX + StartY * this->termSize.ws_row; i < EndX + EndY * this->termSize.ws_row; i++) + { + TerminalCell *cell = &this->Cells[i]; + cell->c = ' '; + cell->attr = {}; + + this->PaintCB(cell, i % this->termSize.ws_row, i / this->termSize.ws_row); + } + } + + void VirtualTerminal::Scroll(unsigned short Lines) + { + assert(this->PaintCB != nullptr); + if (Lines == 0) + return; + + Lines = Lines > this->termSize.ws_col ? this->termSize.ws_col : Lines; + + for (int i = 0; i < ((this->termSize.ws_row * this->termSize.ws_col) - (this->termSize.ws_row * Lines)); i++) + { + this->Cells[i] = this->Cells[i + (this->termSize.ws_row * Lines)]; + this->PaintCB(&this->Cells[i], i % this->termSize.ws_row, i / this->termSize.ws_row); + } + + for (int i = ((this->termSize.ws_row * this->termSize.ws_col) - (this->termSize.ws_row * Lines)); i < this->termSize.ws_row * this->termSize.ws_col; i++) + { + TerminalCell *cell = &this->Cells[i]; + cell->attr = {}; + cell->c = ' '; + + this->PaintCB(cell, i % this->termSize.ws_row, i / this->termSize.ws_row); + } + + // Move the cursor up $lines + if (this->Cursor.Y > 0) + { + this->Cursor.Y -= Lines; + + if (this->Cursor.Y < 0) + this->Cursor.Y = 0; + + if (this->CursorCB != nullptr) + this->CursorCB(&this->Cursor); + } + } + + void VirtualTerminal::NewLine() + { + this->Cursor.X = 0; + this->Cursor.Y++; + + if (this->Cursor.Y >= this->termSize.ws_col) + this->Scroll(1); + + if (this->CursorCB != nullptr) + this->CursorCB(&this->Cursor); + } + + void VirtualTerminal::Append(char c) + { + if (c == '\n') + this->NewLine(); + else if (c == '\r') + { + this->Cursor.X = 0; + if (this->CursorCB != nullptr) + this->CursorCB(&this->Cursor); + } + else if (c == '\t') + { + int n = 8 - (this->Cursor.X % 8); + + for (int i = 0; i < n; i++) + this->Append(' '); + } + else if (c == '\b') + { + if (this->Cursor.X > 0) + { + this->Cursor.X--; + } + else + { + this->Cursor.Y--; + this->Cursor.X = this->termSize.ws_row - 1; + } + + if (this->CursorCB != nullptr) + this->CursorCB(&this->Cursor); + } + else + { + if (this->Cursor.X >= this->termSize.ws_row) + this->NewLine(); + + TerminalCell *cell = &this->Cells[this->Cursor.X + this->Cursor.Y * this->termSize.ws_row]; + cell->c = c; + cell->attr = this->Attribute; + + assert(this->PaintCB != nullptr); + this->PaintCB(cell, this->Cursor.X, this->Cursor.Y); + + this->Cursor.X++; + + if (this->CursorCB != nullptr) + this->CursorCB(&this->Cursor); + } + } + + void VirtualTerminal::csi_cup(ANSIArgument *Args, int ArgsCount) + { + if (ArgsCount == 1 && Args[0].Empty) + { + this->Cursor.X = 0; + this->Cursor.Y = 0; + } + else if (ArgsCount == 2) + { + if (Args[0].Empty) + this->Cursor.Y = 0; + else + this->Cursor.Y = MIN(Args[0].Value - 1, this->termSize.ws_col - 1); + + if (Args[1].Empty) + this->Cursor.Y = 0; + else + this->Cursor.X = MIN(Args[1].Value - 1, this->termSize.ws_row - 1); + } + + if (this->CursorCB != nullptr) + this->CursorCB(&this->Cursor); + } + + void VirtualTerminal::csi_ed(ANSIArgument *Args, int ArgsCount) + { + TerminalCursor cursor = this->Cursor; + + if (Args[0].Empty) + this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, this->termSize.ws_col - 1); + else + { + int attr = Args[0].Value; + + if (attr == 0) + this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, this->termSize.ws_col - 1); + else if (attr == 1) + this->Clear(0, 0, cursor.X, cursor.Y); + else if (attr == 2) + this->Clear(0, 0, this->termSize.ws_row, this->termSize.ws_col - 1); + } + } + + void VirtualTerminal::csi_el(ANSIArgument *Args, int ArgsCount) + { + TerminalCursor cursor = this->Cursor; + + if (Args[0].Empty) + this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, cursor.Y); + else + { + int attr = Args[0].Value; + + if (attr == 0) + this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, cursor.Y); + else if (attr == 1) + this->Clear(0, cursor.Y, cursor.X, cursor.Y); + else if (attr == 2) + this->Clear(0, cursor.Y, this->termSize.ws_row, cursor.Y); + } + } + + void VirtualTerminal::csi_sgr(ANSIArgument *Args, int ArgsCount) + { + for (int i = 0; i < ArgsCount; i++) + { + if (Args[i].Empty || Args[i].Value == 0) + this->Attribute = {}; + else + { + int attr = Args[i].Value; + + if (attr == 1) + this->Attribute.Bright = true; + else if (attr >= 30 && attr <= 37) + this->Attribute.Foreground = (TerminalColor)(attr - 30); + else if (attr >= 40 && attr <= 47) + this->Attribute.Background = (TerminalColor)(attr - 40); + } + } + } + + void VirtualTerminal::csi_cuu(ANSIArgument *Args, int ArgsCount) + { + int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1; + Cursor.Y -= P1; + if (Cursor.Y < 0) + Cursor.Y = 0; + if (CursorCB) + CursorCB(&Cursor); + } + + void VirtualTerminal::csi_cud(ANSIArgument *Args, int ArgsCount) + { + int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1; + Cursor.Y += P1; + if (Cursor.Y >= this->termSize.ws_col) + Cursor.Y = this->termSize.ws_col - 1; + if (CursorCB) + CursorCB(&Cursor); + } + + void VirtualTerminal::csi_cuf(ANSIArgument *Args, int ArgsCount) + { + int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1; + Cursor.X += P1; + if (Cursor.X >= this->termSize.ws_row) + Cursor.X = this->termSize.ws_row - 1; + if (CursorCB) + CursorCB(&Cursor); + } + + void VirtualTerminal::csi_cub(ANSIArgument *Args, int ArgsCount) + { + int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1; + Cursor.X -= P1; + if (Cursor.X < 0) + Cursor.X = 0; + if (CursorCB) + CursorCB(&Cursor); + } + + void VirtualTerminal::csi_cnl(ANSIArgument *Args, int ArgsCount) + { + int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1; + Cursor.Y += P1; + if (Cursor.Y >= this->termSize.ws_col) + Cursor.Y = this->termSize.ws_col - 1; + Cursor.X = 0; + if (CursorCB) + CursorCB(&Cursor); + } + + void VirtualTerminal::csi_cpl(ANSIArgument *Args, int ArgsCount) + { + int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1; + Cursor.Y -= P1; + if (Cursor.Y < 0) + Cursor.Y = 0; + Cursor.X = 0; + if (CursorCB) + CursorCB(&Cursor); + } + + void VirtualTerminal::csi_cha(ANSIArgument *Args, int ArgsCount) + { + int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1; + Cursor.X = P1 - 1; + if (Cursor.X >= this->termSize.ws_row) + Cursor.X = this->termSize.ws_row - 1; + if (CursorCB) + CursorCB(&Cursor); + } + + void VirtualTerminal::Process(char c) + { +#ifdef DEBUG + static int once = 0; + static uint8_t com4 = 0xFF; + if (!once++) + { + com4 = inb(0x2E8); + debug("COM4 is available"); + outb(s_cst(uint16_t, 0x2E8 + 1), 0x00); + outb(s_cst(uint16_t, 0x2E8 + 3), 0x80); + outb(s_cst(uint16_t, 0x2E8 + 0), 0x01); + outb(s_cst(uint16_t, 0x2E8 + 1), 0x00); + outb(s_cst(uint16_t, 0x2E8 + 3), 0x03); + outb(s_cst(uint16_t, 0x2E8 + 2), 0xC7); + outb(s_cst(uint16_t, 0x2E8 + 4), 0x0B); + outb(s_cst(uint16_t, 0x2E8 + 4), 0x0F); + } + if (com4 != 0xFF) + { + while ((inb(s_cst(uint16_t, 0x2E8 + 5)) & 0x20) == 0) + ; + outb(0x2E8, c); + } + + // while (true) + // { + // while ((inb(0x2E8 + 5) & 1) == 0) + // ; + // outb(0x2E8, inb(0x2E8)); + // } +#endif + + ANSIParser *parser = &this->Parser; + + switch (parser->State) + { + case ANSIParser::ParserState::Escape: + { + if (c == '\x1b') + { + parser->State = ANSIParser::ParserState::Bracket; + parser->Index = 0; + parser->Stack[parser->Index].Value = 0; + parser->Stack[parser->Index].Empty = true; + } + else + { + parser->State = ANSIParser::ParserState::Escape; + this->Append(c); + } + break; + } + case ANSIParser::ParserState::Bracket: + { + if (c == '[') + parser->State = ANSIParser::ParserState::Attribute; + else + { + parser->State = ANSIParser::ParserState::Escape; + this->Append(c); + } + break; + } + case ANSIParser::ParserState::Attribute: + { + if (isdigit(c)) + { + parser->Stack[parser->Index].Value *= 10; + parser->Stack[parser->Index].Value += c - '0'; + parser->Stack[parser->Index].Empty = false; + } + else + { + if (parser->Index < 8) + parser->Index++; + + parser->Stack[parser->Index].Value = 0; + parser->Stack[parser->Index].Empty = true; + parser->State = ANSIParser::ParserState::EndValue; + } + break; + } + case ANSIParser::ParserState::EndValue: + break; + default: + assert(!"Invalid parser state"); + } + + if (parser->State == ANSIParser::ParserState::EndValue) + { + if (c == ';') + parser->State = ANSIParser::ParserState::Attribute; + else + { + switch (c) + { + case 'A': + this->csi_cuu(parser->Stack, parser->Index); + break; + case 'B': + this->csi_cud(parser->Stack, parser->Index); + break; + + case 'C': + this->csi_cuf(parser->Stack, parser->Index); + break; + case 'D': + this->csi_cub(parser->Stack, parser->Index); + break; + + case 'E': + this->csi_cnl(parser->Stack, parser->Index); + break; + case 'F': + this->csi_cpl(parser->Stack, parser->Index); + break; + + case 'G': + this->csi_cha(parser->Stack, parser->Index); + break; + case 'd': + fixme("move cursor left P1 columns"); + break; + + case 'H': + this->csi_cup(parser->Stack, parser->Index); + break; + case 'J': + this->csi_ed(parser->Stack, parser->Index); + break; + case 'K': + this->csi_el(parser->Stack, parser->Index); + break; + case 'm': + this->csi_sgr(parser->Stack, parser->Index); + break; + default: + break; + } + parser->State = ANSIParser::ParserState::Escape; + } + } + } + + VirtualTerminal::VirtualTerminal(unsigned short Rows, unsigned short Columns, + unsigned short XPixels, unsigned short YPixels, + PaintCallback _Paint, CursorCallback _Print) + : PaintCB(_Paint), CursorCB(_Print) + { + this->termSize = { + .ws_row = Rows, + .ws_col = Columns, + .ws_xpixel = XPixels, + .ws_ypixel = YPixels, + }; + + /* + - ICRNL - Map Carriage Return to New Line + - IXON - Enable XON/XOFF flow control + + - OPOST - Enable output processing + - ONLCR - Map New Line to Carriage Return - New Line + + - CS8 - 8-bit characters + - CREAD - Enable receiver + - HUPCL - Hang up on last close + + - ECHO - Echo input characters + - ICANON - Enable canonical input (enable line editing) + */ + this->term.c_iflag = /*ICRNL |*/ IXON; + this->term.c_oflag = OPOST | ONLCR; + this->term.c_cflag = CS8 | CREAD | HUPCL; + this->term.c_lflag = ECHO | ICANON; + + this->term.c_cc[VINTR] = 0x03; /* ^C */ + this->term.c_cc[VQUIT] = 0x1C; /* ^\ */ + this->term.c_cc[VERASE] = 0x7F; /* DEL */ + this->term.c_cc[VKILL] = 0x15; /* ^U */ + this->term.c_cc[VEOF] = 0x04; /* ^D */ + this->term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */ + this->term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */ + this->term.c_cc[VSWTC] = 0; /* ^O */ + this->term.c_cc[VSTART] = 0x11; /* ^Q */ + this->term.c_cc[VSTOP] = 0x13; /* ^S */ + this->term.c_cc[VSUSP] = 0x1A; /* ^Z */ + this->term.c_cc[VEOL] = 0x00; /* NUL */ + this->term.c_cc[VREPRINT] = 0x12; /* ^R */ + this->term.c_cc[VDISCARD] = 0x14; /* ^T */ + this->term.c_cc[VWERASE] = 0x17; /* ^W */ + this->term.c_cc[VLNEXT] = 0x19; /* ^Y */ + this->term.c_cc[VEOL2] = 0x7F; /* DEL (or sometimes EOF) */ + + this->Cells = new TerminalCell[Rows * Columns]; + + debug("Allocated %d bytes for terminal cells", + (Rows * Columns) * sizeof(TerminalCell)); + } + + VirtualTerminal::~VirtualTerminal() + { + delete[] this->Cells; + } +} diff --git a/exec/elf/elf_loader.cpp b/exec/elf/elf_loader.cpp index d3ec0dc3..3004647e 100644 --- a/exec/elf/elf_loader.cpp +++ b/exec/elf/elf_loader.cpp @@ -350,7 +350,7 @@ namespace Execute } } - Elf64_Ehdr ELFHeader; + Elf64_Ehdr ELFHeader{}; fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); uintptr_t EntryPoint = ELFHeader.e_entry; debug("Entry point is %#lx", EntryPoint); @@ -808,7 +808,7 @@ namespace Execute while (envp[envc] != nullptr) envc++; - Elf32_Ehdr ELFHeader; + Elf32_Ehdr ELFHeader{}; fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0); std::vector PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP); diff --git a/include/display.hpp b/include/display.hpp index 34ea83e1..32f328a0 100644 --- a/include/display.hpp +++ b/include/display.hpp @@ -184,17 +184,10 @@ namespace Video { private: BootInfo::FramebufferInfo framebuffer; - Font *DefaultFont = nullptr; - Font *CurrentFont = nullptr; - bool ColorIteration = false; - int ColorPickerIteration = 0; void *Buffer; size_t Size; uint32_t Width, Height; - uint32_t Color; - uint32_t CursorX, CursorY; - bool DoNotScroll; bool DirectWrite; uint32_t RegionWidth = 64, RegionHeight = 64; @@ -207,9 +200,6 @@ namespace Video decltype(Height) &GetHeight = Height; BootInfo::FramebufferInfo GetFramebufferStruct() { return framebuffer; } - Font *GetDefaultFont() { return DefaultFont; } - Font *GetCurrentFont(); - void SetCurrentFont(Font *Font); uint16_t GetBitsPerPixel(); size_t GetPitch(); @@ -219,41 +209,12 @@ namespace Video void DrawRectangle(uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height, uint32_t Color); - void Scroll(int Lines); - - void SetDoNotScroll(bool Value) - { - this->DoNotScroll = Value; - } - - void SetBufferCursor(uint32_t X, uint32_t Y) - { - this->CursorX = X; - this->CursorY = Y; - } - - void GetBufferCursor(uint32_t *X, uint32_t *Y) - { - *X = this->CursorX; - *Y = this->CursorY; - } void UpdateRegion(size_t RegionRow, size_t RegionColumn); void MarkRegionDirty(size_t RegionRow, size_t RegionCol); void UpdateBuffer(); - char Print(char Char, - Video::Font *Font = nullptr, - bool WriteToUART = false, - bool IgnoreSpecialChars = false); - - void PrintString(const char *String, - Video::Font *Font = nullptr, - bool WriteToUART = false, - bool IgnoreSpecialChars = false); - Display(BootInfo::FramebufferInfo Info, - bool LoadDefaultFont = true, bool DirectWrite = true); ~Display(); }; diff --git a/include/kcon.hpp b/include/kcon.hpp index fd0df5e4..c57ecd9c 100644 --- a/include/kcon.hpp +++ b/include/kcon.hpp @@ -18,11 +18,130 @@ #ifndef __FENNIX_KERNEL_KERNEL_CONSOLE_H__ #define __FENNIX_KERNEL_KERNEL_CONSOLE_H__ +#include #include +#include namespace KernelConsole { + enum TerminalColor + { + BLACK, + RED, + GREEN, + YELLOW, + BLUE, + MAGENTA, + CYAN, + GREY + }; + + struct ANSIArgument + { + int Value = 0; + bool Empty = true; + }; + + struct ANSIParser + { + enum ParserState + { + Escape, + Bracket, + Attribute, + EndValue + } State = Escape; + + ANSIArgument Stack[8] = {}; + int Index = 0; + }; + + struct TerminalAttribute + { + bool Bright = false; + TerminalColor Background = BLACK; + TerminalColor Foreground = GREY; + }; + + struct TerminalCell + { + char c = '\0'; + TerminalAttribute attr{}; + }; + + struct TerminalCursor + { + long X = 0; + long Y = 0; + }; + + typedef void (*PaintCallback)(TerminalCell *Cell, long X, long Y); + typedef void (*CursorCallback)(TerminalCursor *Cursor); + + class FontRenderer + { + public: + Video::Font *CurrentFont = nullptr; + TerminalCursor Cursor = {0, 0}; + char Paint(long CellX, long CellY, char Char, uint32_t Foreground, uint32_t Background); + }; + + class VirtualTerminal + { + private: + ANSIParser Parser{}; + TerminalAttribute Attribute{}; + + TerminalCell *Cells = nullptr; + TerminalCursor Cursor{}; + + PaintCallback PaintCB = nullptr; + CursorCallback CursorCB = nullptr; + + public: + termios term; + winsize termSize; + + void Clear(unsigned short StartX, unsigned short StartY, unsigned short EndX, unsigned short EndY); + void Scroll(unsigned short Lines); + void NewLine(); + void Append(char c); + void csi_cup(ANSIArgument *Args, int ArgsCount); + void csi_ed(ANSIArgument *Args, int ArgsCount); + void csi_el(ANSIArgument *Args, int ArgsCount); + void csi_sgr(ANSIArgument *Args, int ArgsCount); + void csi_cuu(ANSIArgument *Args, int ArgsCount); + void csi_cud(ANSIArgument *Args, int ArgsCount); + void csi_cuf(ANSIArgument *Args, int ArgsCount); + void csi_cub(ANSIArgument *Args, int ArgsCount); + void csi_cnl(ANSIArgument *Args, int ArgsCount); + void csi_cpl(ANSIArgument *Args, int ArgsCount); + void csi_cha(ANSIArgument *Args, int ArgsCount); + void Process(char c); + + VirtualTerminal(unsigned short Rows, unsigned short Columns, + unsigned short XPixels, unsigned short YPixels, + PaintCallback Paint, CursorCallback Print); + ~VirtualTerminal(); + }; + + /** + * 0 - Default + * 1...11 - User + * ... + * 15 - Panic + */ + extern VirtualTerminal *Terminals[16]; + extern std::atomic CurrentTerminal; + extern int TermColors[]; + extern int TermBrightColors[]; + + bool SetTheme(std::string Theme); + + /* Limited in functionality */ void EarlyInit(); + + /* Full working terminal */ void LateInit(); } diff --git a/include/types.h b/include/types.h index d8e8ce6b..4dcd89c2 100644 --- a/include/types.h +++ b/include/types.h @@ -75,6 +75,8 @@ typedef __builtin_va_list va_list; #define offsetof(type, member) __builtin_offsetof(type, member) +#define RGB_TO_HEX(r, g, b) ((r << 16) | (g << 8) | (b)) + #define MAX(a, b) \ ({ \ __typeof__(a) _a = (a); \ diff --git a/include_std/termios.h b/include_std/termios.h index b22da8fd..93bbcca1 100644 --- a/include_std/termios.h +++ b/include_std/termios.h @@ -170,10 +170,7 @@ struct termios tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; - cc_t c_line; cc_t c_cc[NCCS]; - speed_t c_ispeed; - speed_t c_ospeed; }; struct winsize @@ -184,4 +181,10 @@ struct winsize unsigned short ws_ypixel; }; +struct ttysize +{ + int ts_lines; + int ts_cols; +}; + #endif // !__FENNIX_KERNEL_TERMIOS_H__ diff --git a/kernel.cpp b/kernel.cpp index 887ae5c2..97e5427c 100644 --- a/kernel.cpp +++ b/kernel.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -63,8 +64,9 @@ Driver::Manager *DriverManager = nullptr; EXTERNC void putchar(char c) { - if (Display) - Display->Print(c); + KernelConsole::VirtualTerminal *vt = KernelConsole::CurrentTerminal.load(std::memory_order_acquire); + if (vt != nullptr) + vt->Process(c); else UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(c); } @@ -79,20 +81,20 @@ EXTERNC void _KPrint(const char *Format, va_list Args) if (Nanoseconds != 0) { #if defined(a64) - printf("\eCCCCCC[\e00AEFF%lu.%07lu\eCCCCCC] ", + printf("\x1b[1;30m[\x1b[1;34m%lu.%07lu\x1b[1;30m]\x1b[0m ", Nanoseconds / 10000000, Nanoseconds % 10000000); #elif defined(a32) - printf("\eCCCCCC[\e00AEFF%llu.%07llu\eCCCCCC] ", + printf("\x1b[1;30m[\x1b[1;34m%llu.%07llu\x1b[1;30m]\x1b[0m ", Nanoseconds / 10000000, Nanoseconds % 10000000); #elif defined(aa64) - printf("\eCCCCCC[\e00AEFF%lu.%07lu\eCCCCCC] ", + printf("\x1b[1;30m[\x1b[1;34m%lu.%07lu\x1b[1;30m]\x1b[0m ", Nanoseconds / 10000000, Nanoseconds % 10000000); #endif } } vprintf(Format, Args); - printf("\eCCCCCC\n"); + printf("\x1b[0m\n"); if (!Config.Quiet && Display) Display->UpdateBuffer(); } @@ -119,26 +121,28 @@ EXTERNC void KPrint(const char *Format, ...) EXTERNC NIF void Main() { Display = new Video::Display(bInfo.Framebuffer[0]); + KernelConsole::EarlyInit(); - KPrint("%s - %s [\e058C19%s\eFFFFFF]", + printf("\x1b[H\x1b[2J"); + KPrint("%s - %s [\x1b[32m%s\x1b[0m]", KERNEL_NAME, KERNEL_VERSION, GIT_COMMIT_SHORT); - KPrint("CPU: \e058C19%s \e8822AA%s \e8888FF%s", + KPrint("CPU: \x1b[32m%s \x1b[31m%s \x1b[37m%s", CPU::Hypervisor(), CPU::Vendor(), CPU::Name()); if (Display->GetFramebufferStruct().BitsPerPixel != 32) - KPrint("\eFF5500Framebuffer is not 32 bpp. This may cause issues."); + KPrint("\x1b[1;31mFramebuffer is not 32 bpp. This may cause issues."); if (Display->GetWidth < 640 || Display->GetHeight < 480) { - KPrint("\eFF5500Minimum supported resolution is 640x480!"); - KPrint("\eFF5500Some elements may not be displayed correctly."); + KPrint("\x1b[1;31mMinimum supported resolution is 640x480!"); + KPrint("\x1b[1;31mSome elements may not be displayed correctly."); } debug("CPU: %s %s %s", CPU::Hypervisor(), CPU::Vendor(), CPU::Name()); if (DebuggerIsAttached) - KPrint("\eFFA500Kernel debugger detected."); + KPrint("Kernel debugger detected."); #if defined(a86) && defined(DEBUG) uint8_t lpt1 = inb(0x378); @@ -171,7 +175,7 @@ EXTERNC NIF void Main() if (com4 != 0xFF) KPrint("COM4 is present."); - KPrint("Display: %dx%d %d bpp \eFF0000R:%d %d \e00FF00G: %d %d \e0000FFB: %d %d", + KPrint("Display: %dx%d %d bpp R:%d %d G:%d %d B:%d %d", Display->GetFramebufferStruct().Width, Display->GetFramebufferStruct().Height, Display->GetFramebufferStruct().BitsPerPixel, @@ -236,7 +240,7 @@ EXTERNC NIF void Main() KPrint("Initializing Filesystem"); KernelVFS(); - KPrint("\e058C19################################"); + KPrint("\x1b[1;32m################################"); TaskManager = new Tasking::Task(Tasking::IP(KernelMainThread)); TaskManager->StartScheduler(); CPU::Halt(true); diff --git a/kernel.h b/kernel.h index 3b37da87..463acde4 100644 --- a/kernel.h +++ b/kernel.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #endif diff --git a/kernel_config.cpp b/kernel_config.cpp index 6a5270e1..2144de39 100644 --- a/kernel_config.cpp +++ b/kernel_config.cpp @@ -143,22 +143,22 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) value = cag_option_get_value(&context); if (strcmp(value, "xallocv1") == 0) { - KPrint("\eAAFFAAUsing XallocV1 as memory allocator"); + KPrint("Using XallocV1 as memory allocator"); ModConfig->AllocatorType = Memory::XallocV1; } else if (strcmp(value, "xallocv2") == 0) { - KPrint("\eAAFFAAUsing XallocV2 as memory allocator"); + KPrint("Using XallocV2 as memory allocator"); ModConfig->AllocatorType = Memory::XallocV2; } else if (strcmp(value, "liballoc11") == 0) { - KPrint("\eAAFFAAUsing Liballoc11 as memory allocator"); + KPrint("Using Liballoc11 as memory allocator"); ModConfig->AllocatorType = Memory::liballoc11; } else if (strcmp(value, "pages") == 0) { - KPrint("\eAAFFAAUsing Pages as memory allocator"); + KPrint("Using Pages as memory allocator"); ModConfig->AllocatorType = Memory::Pages; } break; @@ -166,14 +166,14 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) case 'c': { value = cag_option_get_value(&context); - KPrint("\eAAFFAAUsing %s cores", atoi(value) ? value : "all"); + KPrint("Using %s cores", atoi(value) ? value : "all"); ModConfig->Cores = atoi(value); break; } case 'p': { value = cag_option_get_value(&context); - KPrint("\eAAFFAARedirecting I/O APIC interrupts to %s%s", + KPrint("Redirecting I/O APIC interrupts to %s%s", atoi(value) ? "core " : "", atoi(value) ? value : "BSP"); ModConfig->IOAPICInterruptCore = atoi(value); break; @@ -183,17 +183,17 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) value = cag_option_get_value(&context); if (strcmp(value, "multi") == 0) { - KPrint("\eAAFFAAUsing Multi-Tasking Scheduler"); + KPrint("Using Multi-Tasking Scheduler"); ModConfig->SchedulerType = Multi; } else if (strcmp(value, "single") == 0) { - KPrint("\eAAFFAAUsing Single-Tasking Scheduler"); + KPrint("Using Single-Tasking Scheduler"); ModConfig->SchedulerType = Mono; } else { - KPrint("\eAAFFAAUnknown scheduler: %s", value); + KPrint("Unknown scheduler: %s", value); ModConfig->SchedulerType = Multi; } break; @@ -202,14 +202,14 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) { value = cag_option_get_value(&context); strncpy(ModConfig->DriverDirectory, value, strlen(value)); - KPrint("\eAAFFAAUsing %s as module directory", value); + KPrint("Using %s as module directory", value); break; } case 'i': { value = cag_option_get_value(&context); strncpy(ModConfig->InitPath, value, strlen(value)); - KPrint("\eAAFFAAUsing %s as init program", value); + KPrint("Using %s as init program", value); break; } case 'y': @@ -218,7 +218,7 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) strcmp(value, "true") == 0 ? ModConfig->UseLinuxSyscalls = true : ModConfig->UseLinuxSyscalls = false; - KPrint("\eAAFFAAUse Linux syscalls by default: %s", value); + KPrint("Use Linux syscalls by default: %s", value); break; } case 'o': @@ -227,7 +227,7 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) strcmp(value, "true") == 0 ? ModConfig->InterruptsOnCrash = true : ModConfig->InterruptsOnCrash = false; - KPrint("\eAAFFAAInterrupts on crash: %s", value); + KPrint("Interrupts on crash: %s", value); break; } case 'l': @@ -236,7 +236,7 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) strcmp(value, "true") == 0 ? ModConfig->UnlockDeadLock = true : ModConfig->UnlockDeadLock = false; - KPrint("\eAAFFAAUnlocking the deadlock after 10 retries"); + KPrint("Unlocking the deadlock after 10 retries"); break; } case 's': @@ -244,7 +244,7 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) value = cag_option_get_value(&context); strcmp(value, "true") == 0 ? ModConfig->SIMD = true : ModConfig->SIMD = false; - KPrint("\eAAFFAASingle Instruction, Multiple Data (SIMD): %s", value); + KPrint("Single Instruction, Multiple Data (SIMD): %s", value); break; } case 'b': @@ -252,7 +252,7 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) value = cag_option_get_value(&context); strcmp(value, "true") == 0 ? ModConfig->Quiet = true : ModConfig->Quiet = false; - KPrint("\eAAFFAAQuiet boot: %s", value); + KPrint("Quiet boot: %s", value); break; } case 'h': @@ -260,12 +260,12 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) KPrint("\n---------------------------------------------------------------------------\nUsage: fennix.elf [OPTION]...\nKernel configuration."); cag_option_print(ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), nullptr); - KPrint("\eFF2200System Halted."); + KPrint("\x1b[1;31;41mSystem Halted."); CPU::Stop(); } default: { - KPrint("\eFF2200Unknown option: %c", identifier); + KPrint("\x1b[31mUnknown option: %c", identifier); break; } } diff --git a/kernel_thread.cpp b/kernel_thread.cpp index 96717927..186c690e 100644 --- a/kernel_thread.cpp +++ b/kernel_thread.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ void KernelMainThread() DriverManager->PreloadDrivers(); DriverManager->LoadAllDrivers(); + KernelConsole::LateInit(); #ifdef DEBUG // TaskManager->CreateThread(thisProcess, // Tasking::IP(KShellThread)) @@ -96,12 +98,12 @@ void KernelMainThread() int tid = SpawnInit(); if (tid < 0) { - KPrint("\eE85230Failed to start %s! Error: %s (%d)", + KPrint("\x1b[1;37;41mFailed to start %s! Error: %s (%d)", Config.InitPath, strerror(tid), tid); goto Exit; } - KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", + KPrint("Waiting for \x1b[32m%s\x1b[0m to start...", Config.InitPath); thisThread->SetPriority(Tasking::Idle); @@ -110,7 +112,7 @@ void KernelMainThread() TaskManager->WaitForThread(initThread); ExitCode = initThread->GetExitCode(); Exit: - KPrint("\eE85230Userspace process exited with code %d (%#x)", + KPrint("\x1b[31mUserspace process exited with code %d (%#x)", ExitCode, ExitCode < 0 ? -ExitCode : ExitCode); KPrint("Dropping to kernel shell"); diff --git a/kshell/cmds.hpp b/kshell/cmds.hpp index 55c5e4bc..e79ef58e 100644 --- a/kshell/cmds.hpp +++ b/kshell/cmds.hpp @@ -43,6 +43,7 @@ void cmd_lsmod(const char *args); void cmd_modinfo(const char *args); void cmd_panic(const char *args); void cmd_dump(const char *args); +void cmd_theme(const char *args); #define IF_ARG(x) strcmp(args, x) == 0 diff --git a/kshell/commands/clear.cpp b/kshell/commands/clear.cpp index 5fc2474f..48beb99b 100644 --- a/kshell/commands/clear.cpp +++ b/kshell/commands/clear.cpp @@ -21,6 +21,5 @@ void cmd_clear(const char *) { - Display->SetBufferCursor(0, 0); - Display->ClearBuffer(); + printf("\x1b[2J"); } diff --git a/kshell/commands/ls.cpp b/kshell/commands/ls.cpp index baf26c4e..e7c7c98c 100644 --- a/kshell/commands/ls.cpp +++ b/kshell/commands/ls.cpp @@ -26,19 +26,19 @@ using namespace vfs; const char *ColorNodeType(FileNode *node) { if (node->IsRegularFile()) - return "\eCCCCCC"; + return "\x1b[32m"; else if (node->IsDirectory()) - return "\e3871F5"; + return "\x1b[34m"; else if (node->IsBlockDevice()) - return "\eE8CD1E"; + return "\x1b[33m"; else if (node->IsCharacterDevice()) - return "\e86E01F"; + return "\x1b[33m"; else if (node->IsFIFO()) - return "\eE0991F"; + return "\x1b[33m"; else if (node->IsSymbolicLink()) - return "\e1FB9E0"; + return "\x1b[35m"; else - return "\eF72020"; + return "\x1b[0m"; } __no_sanitize("alignment") size_t MaxNameLength(FileNode *nodes) @@ -100,7 +100,7 @@ __no_sanitize("alignment") void PrintLS(FileNode *node) offset += read / sizeof(kdirent); } - printf("\eCCCCCC\n"); + printf("\x1b[0m\n"); delete[] dirBuffer; } diff --git a/kshell/commands/theme.cpp b/kshell/commands/theme.cpp new file mode 100644 index 00000000..8bc10aeb --- /dev/null +++ b/kshell/commands/theme.cpp @@ -0,0 +1,25 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include "../cmds.hpp" + +#include "../../kernel.h" + +void cmd_theme(const char *args) +{ + KernelConsole::SetTheme(args); +} diff --git a/kshell/commands/top.cpp b/kshell/commands/top.cpp index 0f734770..5ee7e402 100644 --- a/kshell/commands/top.cpp +++ b/kshell/commands/top.cpp @@ -41,16 +41,16 @@ const char *TaskStateStrings[] = { void cmd_top(const char *) { - printf("\e9400A1PID \e9CA100Name \e00A15BState \eCCCCCCPriority Memory Usage CPU Usage\n"); + printf("PID Name State Priority Memory Usage CPU Usage\n"); foreach (auto Proc in TaskManager->GetProcessList()) { #if defined(a64) - printf("\e9400A1%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld KiB %ld\n", + printf("%-4d %-20s %s %d %ld KiB %ld\n", Proc->ID, Proc->Name, TaskStateStrings[Proc->State.load()], Proc->Info.Priority, TO_KiB(Proc->GetSize()), Proc->Info.UserTime + Proc->Info.KernelTime); #elif defined(a32) - printf("\e9400A1%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %lld KiB %lld\n", + printf("%-4d %-20s %s %d %lld KiB %lld\n", Proc->ID, Proc->Name, TaskStateStrings[Proc->State.load()], Proc->Info.Priority, TO_KiB(Proc->GetSize()), Proc->Info.UserTime + Proc->Info.KernelTime); @@ -59,12 +59,12 @@ void cmd_top(const char *) foreach (auto Thrd in Proc->Threads) { #if defined(a64) - printf(" \eA80011%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld KiB %ld\n", + printf(" %-4d %-20s %s %d %ld KiB %ld\n", Thrd->ID, Thrd->Name, TaskStateStrings[Thrd->State.load()], Thrd->Info.Priority, TO_KiB(Thrd->GetSize()), Thrd->Info.UserTime + Thrd->Info.KernelTime); #elif defined(a32) - printf(" \eA80011%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %lld KiB %lld\n", + printf(" %-4d %-20s %s %d %lld KiB %lld\n", Thrd->ID, Thrd->Name, TaskStateStrings[Thrd->State.load()], Thrd->Info.Priority, TO_KiB(Thrd->GetSize()), Thrd->Info.UserTime + Thrd->Info.KernelTime); diff --git a/kshell/shell.cpp b/kshell/shell.cpp index 1942c80c..c954669a 100644 --- a/kshell/shell.cpp +++ b/kshell/shell.cpp @@ -77,89 +77,17 @@ static Command commands[] = { {"depmod", nullptr}, {"panic", cmd_panic}, {"dump", cmd_dump}, + {"theme", cmd_theme}, {"builtin", __cmd_builtin}, }; -std::atomic_uint32_t CurX = 0x10, CurY = 0x10; -std::atomic_bool CurBlinking = false; -std::atomic_bool CurHalt = true; -std::atomic_uint64_t BlinkerSleep = 0; - -NewLock(BlinkerLock); - -void PrintBlinker(uint32_t fx, uint32_t fy) +void KShellThread() { - for (uint32_t i = 0; i < fx; i++) - { - for (uint32_t j = 0; j < fy; j++) - { - uint32_t px = CurX.load() + i; - uint32_t py = CurY.load() + j; - uint32_t color = Display->GetPixel(px, py); - Display->SetPixel(px, py, ~color); - } - } -} + assert(!ShellLock.Locked()); + ShellLock.Lock(__FUNCTION__); -void UpdateBlinker(bool force = false) -{ - SmartLock(BlinkerLock); - if (CurBlinking.load() || force) - { - uint32_t fx = 0, fy = 0; - if (unlikely(fx == 0 || fy == 0)) - { - fx = Display->GetCurrentFont()->GetInfo().Width; - fy = Display->GetCurrentFont()->GetInfo().Height; - } - - PrintBlinker(fx, fy); - CurBlinking.store(force); - Display->UpdateBuffer(); - } -} - -void CursorBlink() -{ - uint32_t fx, fy; - fx = Display->GetCurrentFont()->GetInfo().Width; - fy = Display->GetCurrentFont()->GetInfo().Height; - while (true) - { - if (CurHalt.load() || - BlinkerSleep.load() > TimeManager->GetCounter()) - { - TaskManager->Sleep(250); - continue; - } - - { - SmartLock(BlinkerLock); - PrintBlinker(fx, fy); - CurBlinking.store(!CurBlinking.load()); - Display->UpdateBuffer(); - } - TaskManager->Sleep(500); - - { - SmartLock(BlinkerLock); - PrintBlinker(fx, fy); - CurBlinking.store(!CurBlinking.load()); - Display->UpdateBuffer(); - } - TaskManager->Sleep(500); - } -} - -void StartKernelShell() -{ - if (ShellLock.Locked()) - return; - SmartLock(ShellLock); - - debug("Starting kernel shell..."); KPrint("Starting kernel shell..."); - thisThread->SetPriority(Tasking::TaskPriority::High); + thisThread->SetPriority(Tasking::TaskPriority::Normal); std::string strBuf = ""; std::vector history; @@ -168,7 +96,8 @@ void StartKernelShell() bool upperCase = false; bool tabDblPress = false; - FileNode *kfd = fs->GetByPath("/dev/input/keyboard", fs->GetRoot(0)); + const char *keyDevPath = "/dev/input/keyboard"; + FileNode *kfd = fs->GetByPath(keyDevPath, fs->GetRoot(0)); if (kfd == nullptr) { KPrint("Failed to open keyboard device!"); @@ -179,12 +108,14 @@ void StartKernelShell() auto strBufBck = [&]() { for (size_t i = 0; i < strBuf.size(); i++) - Display->Print('\b'); + { + putchar('\b'); + putchar(' '); + putchar('\b'); + } }; - std::thread thd(CursorBlink); - - printf("Using \eCA21F6/dev/key\eCCCCCC for keyboard input.\n"); + printf("Using \x1b[1;34m%s\x1b[0m for keyboard input.\n", keyDevPath); while (true) { size_t bsCount = 0; @@ -198,26 +129,20 @@ void StartKernelShell() cwd = fs->GetRoot(0); std::string cwdStr = fs->GetByNode(cwd); - printf("\e34C6EB%s@%s:%s$ \eCCCCCC", + printf("\x1b[1;34m%s@%s:%s$ \x1b[0m", "kernel", "fennix", cwdStr.c_str()); - Display->UpdateBuffer(); - - Display->GetBufferCursor(&homeX, &homeY); KeyboardReport scBuf{}; ssize_t nBytes; while (true) { - uint32_t __cx, __cy; - Display->GetBufferCursor(&__cx, &__cy); - CurX.store(__cx); - CurY.store(__cy); - CurHalt.store(false); - nBytes = kfd->Read(&scBuf, sizeof(KeyboardReport), 0); if (nBytes == 0) + { + debug("Empty read from keyboard device!"); continue; + } if (nBytes < (ssize_t)sizeof(KeyboardReport)) { KPrint("Failed to read from keyboard device: %s", @@ -225,10 +150,6 @@ void StartKernelShell() return; } - BlinkerSleep.store(TimeManager->CalculateTarget(250, Time::Units::Milliseconds)); - CurHalt.store(true); - UpdateBlinker(); - const KeyScanCodes &sc = scBuf.Key; switch (sc & ~KEY_PRESSED) { @@ -263,28 +184,14 @@ void StartKernelShell() tabDblPress = false; if (strBuf.size() == 0) { - if (unseekX != 0 || unseekY != 0) - { - Display->SetBufferCursor(unseekX, unseekY); - unseekX = unseekY = 0; - } - for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) printf("%s ", commands[i].Name); - Display->Print('\n'); - Display->UpdateBuffer(); + putchar('\n'); goto SecLoopEnd; } - if (unseekX != 0 || unseekY != 0) - { - Display->SetBufferCursor(unseekX, unseekY); - unseekX = unseekY = 0; - } - strBufBck(); - Display->UpdateBuffer(); for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { @@ -293,9 +200,8 @@ void StartKernelShell() strBuf = commands[i].Name; for (size_t i = 0; i < strlen(strBuf.c_str()); i++) - Display->Print(strBuf[i]); + putchar(strBuf[i]); seekCount = bsCount = strBuf.size(); - Display->UpdateBuffer(); break; } continue; @@ -312,31 +218,24 @@ void StartKernelShell() { debug("seekCount == bsCount (%d == %d)", seekCount, bsCount); - Display->Print('\b'); + putchar('\b'); + putchar(' '); + putchar('\b'); strBuf.pop_back(); seekCount = --bsCount; - Display->UpdateBuffer(); continue; } - uint32_t tmpX, tmpY; - Display->GetBufferCursor(&tmpX, &tmpY); - - Display->SetBufferCursor(unseekX, unseekY); strBufBck(); size_t strSeek = seekCount ? seekCount - 1 : 0; seekCount = strSeek; debug("strSeek: %d: %s", strSeek, strBuf.c_str()); strBuf.erase(strSeek); - Display->PrintString(strBuf.c_str()); + printf("%s", strBuf.c_str()); debug("after strBuf: %s", strBuf.c_str()); - uint32_t fx = Display->GetCurrentFont()->GetInfo().Width; - Display->SetBufferCursor(tmpX - fx, tmpY); - unseekX -= fx; bsCount--; - Display->UpdateBuffer(); continue; } case KEY_DELETE: @@ -354,20 +253,13 @@ void StartKernelShell() continue; } - uint32_t tmpX, tmpY; - Display->GetBufferCursor(&tmpX, &tmpY); - - Display->SetBufferCursor(unseekX, unseekY); strBufBck(); debug("seekCount: %d: %s", seekCount, strBuf.c_str()); strBuf.erase(seekCount); - Display->PrintString(strBuf.c_str()); + printf("%s", strBuf.c_str()); debug("after strBuf: %s", strBuf.c_str()); - Display->SetBufferCursor(tmpX, tmpY); - unseekX -= Display->GetCurrentFont()->GetInfo().Width; bsCount--; - Display->UpdateBuffer(); continue; } case KEY_UP_ARROW: @@ -383,19 +275,16 @@ void StartKernelShell() if (unseekX != 0 || unseekY != 0) { - Display->SetBufferCursor(unseekX, unseekY); unseekX = unseekY = 0; } strBufBck(); - Display->UpdateBuffer(); strBuf = history[hIdx]->c_str(); for (size_t i = 0; i < strlen(strBuf.c_str()); i++) - Display->Print(strBuf[i]); + putchar(strBuf[i]); seekCount = bsCount = strBuf.size(); - Display->UpdateBuffer(); continue; } case KEY_DOWN_ARROW: @@ -410,35 +299,26 @@ void StartKernelShell() if (hIdx == history.size() - 1) { if (unseekX != 0 || unseekY != 0) - { - Display->SetBufferCursor(unseekX, unseekY); unseekX = unseekY = 0; - } hIdx++; strBufBck(); seekCount = bsCount = strBuf.size(); - Display->UpdateBuffer(); continue; } if (unseekX != 0 || unseekY != 0) - { - Display->SetBufferCursor(unseekX, unseekY); unseekX = unseekY = 0; - } strBufBck(); - Display->UpdateBuffer(); hIdx++; strBuf = history[hIdx]->c_str(); for (size_t i = 0; i < strlen(strBuf.c_str()); i++) - Display->Print(strBuf[i]); + putchar(strBuf[i]); seekCount = bsCount = strBuf.size(); - Display->UpdateBuffer(); continue; } case KEY_LEFT_ARROW: @@ -446,7 +326,6 @@ void StartKernelShell() if (!(sc & KEY_PRESSED)) continue; - UpdateBlinker(); if (seekCount == 0) continue; @@ -454,9 +333,6 @@ void StartKernelShell() seekCount--; - if (unseekX == 0 && unseekY == 0) - Display->GetBufferCursor(&unseekX, &unseekY); - if (ctrlDown) { uint32_t offset = 0; @@ -474,27 +350,9 @@ void StartKernelShell() } seekCount++; debug("offset: %d; seekCount: %d", offset, seekCount); - - uint32_t fx = Display->GetCurrentFont()->GetInfo().Width; - uint32_t cx, cy; - Display->GetBufferCursor(&cx, &cy); - Display->SetBufferCursor(cx - (fx * offset), cy); - CurX.store(cx - (fx * offset)); - CurY.store(cy); - UpdateBlinker(true); - Display->UpdateBuffer(); continue; } - uint32_t cx, cy; - Display->GetBufferCursor(&cx, &cy); - uint32_t fx = Display->GetCurrentFont()->GetInfo().Width; - Display->SetBufferCursor(cx - fx, cy); - - CurX.store(cx - fx); - CurY.store(cy); - UpdateBlinker(true); - Display->UpdateBuffer(); continue; } case KEY_RIGHT_ARROW: @@ -502,16 +360,12 @@ void StartKernelShell() if (!(sc & KEY_PRESSED)) continue; - UpdateBlinker(); if (seekCount == bsCount) continue; seekCount++; debug("orig seekCount: %d", seekCount); - if (unseekX == 0 && unseekY == 0) - Display->GetBufferCursor(&unseekX, &unseekY); - if (ctrlDown) { uint32_t offset = 0; @@ -528,28 +382,9 @@ void StartKernelShell() seekCount--; debug("offset: %d; seekCount: %d", offset, seekCount); - - uint32_t fx = Display->GetCurrentFont()->GetInfo().Width; - uint32_t cx, cy; - Display->GetBufferCursor(&cx, &cy); - Display->SetBufferCursor(cx + (fx * offset), cy); - - CurX.store(cx + (fx * offset)); - CurY.store(cy); - UpdateBlinker(true); - Display->UpdateBuffer(); continue; } - uint32_t cx, cy; - Display->GetBufferCursor(&cx, &cy); - uint32_t fx = Display->GetCurrentFont()->GetInfo().Width; - Display->SetBufferCursor(cx + fx, cy); - - CurX.store(cx + fx); - CurY.store(cy); - Display->UpdateBuffer(); - UpdateBlinker(true); continue; } case KEY_HOME: @@ -560,20 +395,9 @@ void StartKernelShell() if (homeX == 0 || homeY == 0) continue; - UpdateBlinker(); - if (unseekX == 0 || unseekY == 0) - Display->GetBufferCursor(&unseekX, &unseekY); - - Display->SetBufferCursor(homeX, homeY); - seekCount = 0; debug("seekCount set to 0"); - - CurX.store(homeX); - CurY.store(homeY); - Display->UpdateBuffer(); - UpdateBlinker(true); continue; } case KEY_END: @@ -584,16 +408,8 @@ void StartKernelShell() if (unseekX == 0 || unseekY == 0) continue; - UpdateBlinker(); - Display->SetBufferCursor(unseekX, unseekY); seekCount = bsCount; - debug("seekCount set to bsCount (%d)", bsCount); - - CurX.store(unseekX); - CurY.store(unseekY); - Display->UpdateBuffer(); - UpdateBlinker(true); continue; } default: @@ -614,20 +430,18 @@ void StartKernelShell() { case 'C': { - Display->Print('^'); - Display->Print('C'); - Display->Print('\n'); + putchar('^'); + putchar('C'); + putchar('\n'); fixme("No SIGINT handler yet."); - Display->UpdateBuffer(); goto SecLoopEnd; } case 'D': { - Display->Print('^'); - Display->Print('D'); - Display->Print('\n'); + putchar('^'); + putchar('D'); + putchar('\n'); fixme("No SIGKILL handler yet."); - Display->UpdateBuffer(); goto SecLoopEnd; } default: @@ -637,7 +451,7 @@ void StartKernelShell() if (c == '\n') { - Display->Print(c); + putchar(c); if (strBuf.length() > 0) { std::string *hBuff = new std::string(strBuf.c_str()); @@ -648,34 +462,23 @@ void StartKernelShell() } else if (seekCount >= bsCount) { - Display->Print(c); + putchar(c); strBuf += c; seekCount = ++bsCount; } else { - uint32_t tmpX, tmpY; - Display->GetBufferCursor(&tmpX, &tmpY); - - if (unseekX != 0 && unseekY != 0) - Display->SetBufferCursor(unseekX, unseekY); strBufBck(); - // size_t strSeek = seekCount ? seekCount - 1 : 0; debug("seekCount: %d; \"%s\"", seekCount, strBuf.c_str()); strBuf.insert(seekCount, (size_t)1, c); - Display->PrintString(strBuf.c_str()); + printf("%s", strBuf.c_str()); debug("after strBuf: %s (seek and bs is +1 [seek: %d; bs: %d])", strBuf.c_str(), seekCount + 1, bsCount + 1); - uint32_t fx = Display->GetCurrentFont()->GetInfo().Width; - Display->SetBufferCursor(tmpX + fx, tmpY); - unseekX += fx; seekCount++; bsCount++; } - - Display->UpdateBuffer(); } SecLoopEnd: @@ -817,10 +620,5 @@ void StartKernelShell() printf("%s: command not found\n", cmd_only.c_str()); } -} - -void KShellThread() -{ - StartKernelShell(); inf_loop; } diff --git a/storage/devices/tty/ptmx.cpp b/storage/devices/tty/ptmx.cpp index c471efba..01ea4423 100644 --- a/storage/devices/tty/ptmx.cpp +++ b/storage/devices/tty/ptmx.cpp @@ -59,7 +59,7 @@ namespace vfs PTMXDevice::PTMXDevice() { - + fixme("PTMXDevice"); // /* c rw- rw- rw- */ // mode_t mode = S_IRUSR | S_IWUSR | // S_IRGRP | S_IWGRP | diff --git a/storage/filesystem.cpp b/storage/filesystem.cpp index 6e2ee0f6..6fce9b6f 100644 --- a/storage/filesystem.cpp +++ b/storage/filesystem.cpp @@ -209,6 +209,7 @@ namespace vfs std::string Virtual::GetByNode(FileNode *Node) { + assert(Node != nullptr); if (Node->Parent == nullptr) { if (Node->Node->Flags & I_FLAG_ROOT) diff --git a/storage/virtual.cpp b/storage/virtual.cpp index 4d43f4cc..5bb9898e 100644 --- a/storage/virtual.cpp +++ b/storage/virtual.cpp @@ -29,10 +29,7 @@ namespace vfs min: 0 - 1 - /proc/self - 2 - /dev/null - 3 - /dev/zero - 4 - /dev/random - 5 - /dev/mem + ... */ int __vfs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) @@ -176,8 +173,6 @@ namespace vfs self->Node->Device = FileSystemRoots->Node.Device; self->Node->SetDevice(0, 1); self->Node->Flags = iFlags; - - new vfs::PTMXDevice(); } dev_t Virtual::EarlyReserveDevice() diff --git a/tests/stress.cpp b/tests/stress.cpp index 9cdf92b6..f086a278 100644 --- a/tests/stress.cpp +++ b/tests/stress.cpp @@ -78,14 +78,14 @@ void StressKernel() Tasking::PCB *pcb = nullptr; if (TO_MiB(KernelAllocator.GetFreeMemory()) < 20) { - KPrint("\eE85230Not enough memory left!"); + KPrint("\x1b[1;31;41mNot enough memory left!"); goto End; } ptr = KernelAllocator.RequestPages(TO_PAGES(chunk)); if (ptr == nullptr) { - KPrint("\eE85230Failed to allocate memory!"); + KPrint("\x1b[1;31;41mFailed to allocate memory!"); KPrint("Score is: %d MiB (current is %d MiB)", TO_MiB(highestScore.load()), TO_MiB(totalAllocated.load())); continue; diff --git a/tests/taskmgr.cpp b/tests/taskmgr.cpp index fca16b46..b87e96b9 100644 --- a/tests/taskmgr.cpp +++ b/tests/taskmgr.cpp @@ -123,8 +123,9 @@ void TaskMgr() } uint32_t tmpX, tmpY; - Display->GetBufferCursor(&tmpX, &tmpY); - Display->SetBufferCursor(0, 0); + fixme("cursor 127-128; 179"); + // Display->GetBufferCursor(&tmpX, &tmpY); + // Display->SetBufferCursor(0, 0); printf("\eF02C21Task Manager\n"); static uint64_t OldSystemTime = 0; foreach (auto Proc in TaskManager->GetProcessList()) @@ -175,7 +176,7 @@ void TaskMgr() #endif if (sanity > 1000) sanity = 0; - Display->SetBufferCursor(tmpX, tmpY); + // Display->SetBufferCursor(tmpX, tmpY); if (!Config.Quiet) Display->UpdateBuffer();