diff --git a/Architecture/amd64/DifferentiatedSystemDescriptionTable.cpp b/Architecture/amd64/DifferentiatedSystemDescriptionTable.cpp index 6d8b9777..3cb9bdf2 100644 --- a/Architecture/amd64/DifferentiatedSystemDescriptionTable.cpp +++ b/Architecture/amd64/DifferentiatedSystemDescriptionTable.cpp @@ -61,15 +61,10 @@ namespace ACPI } else if (Event & ACPI_POWER_BUTTON) { - BeforeShutdown(); - this->Shutdown(); - Time::Clock tm = Time::ReadClock(); - while (tm.Second == Time::ReadClock().Second) - ; - outw(0xB004, 0x2000); - outw(0x604, 0x2000); - outw(0x4004, 0x3400); - CPU::Stop(); + if (TaskManager) + TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)KST_Shutdown); + else + KernelShutdownThread(false); } else if (Event & ACPI_SLEEP_BUTTON) { diff --git a/Core/Power.cpp b/Core/Power.cpp index 37435d5d..488b60b5 100644 --- a/Core/Power.cpp +++ b/Core/Power.cpp @@ -14,8 +14,6 @@ namespace Power { void Power::Reboot() { - BeforeShutdown(); - if (((ACPI::ACPI *)this->acpi)->FADT) if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) ((ACPI::DSDT *)this->dsdt)->Reboot(); @@ -44,8 +42,6 @@ namespace Power void Power::Shutdown() { - BeforeShutdown(); - if (((ACPI::ACPI *)this->acpi)->FADT) if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) ((ACPI::DSDT *)this->dsdt)->Shutdown(); diff --git a/GUI/GraphicalUserInterface.cpp b/GUI/GraphicalUserInterface.cpp index 1148f9aa..9d269480 100644 --- a/GUI/GraphicalUserInterface.cpp +++ b/GUI/GraphicalUserInterface.cpp @@ -636,6 +636,7 @@ namespace GraphicalUserInterface GUI::~GUI() { + debug("Destructor called"); delete this->mem, this->mem = nullptr; delete this->BackBuffer, this->BackBuffer = nullptr; delete this->DesktopBuffer, this->DesktopBuffer = nullptr; diff --git a/KThread.cpp b/KThread.cpp index 74ba17a1..b10c9e6d 100644 --- a/KThread.cpp +++ b/KThread.cpp @@ -8,6 +8,14 @@ #include #include +#define STB_IMAGE_IMPLEMENTATION +#define STBI_NO_STDIO +#define STBI_NO_LINEAR +#define STBI_NO_THREAD_LOCALS +#define STBI_NO_HDR +#define STBI_ONLY_TGA +#include + #include "DAPI.hpp" #include "Fex.hpp" @@ -24,6 +32,8 @@ VirtualFileSystem::Node *DevFS = nullptr; VirtualFileSystem::Node *MntFS = nullptr; VirtualFileSystem::Node *ProcFS = nullptr; +NewLock(ShutdownLock); + #ifdef DEBUG void TreeFS(Node *node, int Depth) { @@ -31,7 +41,8 @@ void TreeFS(Node *node, int Depth) foreach (auto Chld in node->Children) { printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name); - Display->SetBuffer(0); + if (!Config.BootAnimation) + Display->SetBuffer(0); TaskManager->Sleep(100); TreeFS(Chld, Depth + 1); } @@ -102,7 +113,8 @@ void TaskMgr() if (sanity > 1000) sanity = 0; Display->SetBufferCursor(0, tmpX, tmpY); - Display->SetBuffer(0); + if (!Config.BootAnimation) + Display->SetBuffer(0); CPU::Interrupts(CPU::Enable); } } @@ -130,10 +142,185 @@ Execute::SpawnData SpawnInit() return Execute::Spawn(Config.InitPath, argv, envp); } +/* Files: 0.tga 1.tga ... 40.tga */ +void *Frames[41]; +uint32_t FrameSizes[41]; +uint32_t FrameCount = 1; + +void BootLogoAnimationThread() +{ + char BootAnimPath[16]; + while (FrameCount < 41) + { + sprintf(BootAnimPath, "%d.tga", FrameCount); + std::shared_ptr ba = bootanim_vfs->Open(BootAnimPath); + if (ba->Status != FileStatus::OK) + { + bootanim_vfs->Close(ba); + debug("Failed to load boot animation frame %s", BootAnimPath); + break; + } + + FrameSizes[FrameCount] = ba->node->Length; + Frames[FrameCount] = new uint8_t[ba->node->Length]; + memcpy((void *)Frames[FrameCount], (void *)ba->node->Address, ba->node->Length); + bootanim_vfs->Close(ba); + FrameCount++; + } + + uint32_t DispX = Display->GetBuffer(1)->Width; + uint32_t DispY = Display->GetBuffer(1)->Height; + + for (size_t i = 1; i < FrameCount; i++) + { + int x, y, channels; + + if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels)) + continue; + + uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels, 4); + + if (img == NULL) + continue; + + int offsetX = DispX / 2 - x / 2; + int offsetY = DispY / 2 - y / 2; + + for (int i = 0; i < x * y; i++) + { + uint32_t pixel = ((uint32_t *)img)[i]; + uint8_t r = (pixel >> 16) & 0xFF; + uint8_t g = (pixel >> 8) & 0xFF; + uint8_t b = (pixel >> 0) & 0xFF; + uint8_t a = (pixel >> 24) & 0xFF; + + if (a != 0xFF) + { + r = (r * a) / 0xFF; + g = (g * a) / 0xFF; + b = (b * a) / 0xFF; + } + + Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, (r << 16) | (g << 8) | (b << 0), 1); + } + + free(img); + Display->SetBuffer(1); + } + + int brightness = 100; + while (brightness >= 0) + { + brightness -= 10; + Display->SetBrightness(brightness, 1); + Display->SetBuffer(1); + } +} + +void ExitLogoAnimationThread() +{ + Display->SetBrightness(100, 1); + Display->SetBuffer(1); + + /* Files: 26.tga 25.tga ... 1.tga */ + uint32_t DispX = Display->GetBuffer(1)->Width; + uint32_t DispY = Display->GetBuffer(1)->Height; + + // for (size_t i = 26; i > 0; i--) + // { + // int x, y, channels; + + // if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels)) + // continue; + + // uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels, 4); + + // if (img == NULL) + // continue; + + // int offsetX = DispX / 2 - x / 2; + // int offsetY = DispY / 2 - y / 2; + + // for (int i = 0; i < x * y; i++) + // { + // uint32_t pixel = ((uint32_t *)img)[i]; + // uint8_t r = (pixel >> 16) & 0xFF; + // uint8_t g = (pixel >> 8) & 0xFF; + // uint8_t b = (pixel >> 0) & 0xFF; + // uint8_t a = (pixel >> 24) & 0xFF; + + // if (a != 0xFF) + // { + // r = (r * a) / 0xFF; + // g = (g * a) / 0xFF; + // b = (b * a) / 0xFF; + // } + + // Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, (r << 16) | (g << 8) | (b << 0), 1); + // } + + // free(img); + // Display->SetBuffer(1); + // } + + for (size_t i = 40; i > 25; i--) + { + int x, y, channels; + + if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels)) + continue; + + uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels, 4); + + if (img == NULL) + continue; + + int offsetX = DispX / 2 - x / 2; + int offsetY = DispY / 2 - y / 2; + + for (int i = 0; i < x * y; i++) + { + uint32_t pixel = ((uint32_t *)img)[i]; + uint8_t r = (pixel >> 16) & 0xFF; + uint8_t g = (pixel >> 8) & 0xFF; + uint8_t b = (pixel >> 0) & 0xFF; + uint8_t a = (pixel >> 24) & 0xFF; + + if (a != 0xFF) + { + r = (r * a) / 0xFF; + g = (g * a) / 0xFF; + b = (b * a) / 0xFF; + } + + Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, (r << 16) | (g << 8) | (b << 0), 1); + } + + free(img); + Display->SetBuffer(1); + } + + int brightness = 100; + while (brightness >= 0) + { + brightness -= 10; + Display->SetBrightness(brightness, 1); + Display->SetBuffer(1); + } +} + void KernelMainThread() { TaskManager->GetCurrentThread()->SetPriority(Tasking::Critical); + Tasking::TCB *blaThread = nullptr; + + if (Config.BootAnimation) + { + blaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)BootLogoAnimationThread); + blaThread->Rename("Logo Animation"); + } + #ifdef DEBUG /* TODO: This should not be enabled because it may cause a deadlock. Not sure where or how. */ // Tasking::PCB *tskMgr = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), "Debug Task Manager", Tasking::TaskTrustLevel::Kernel); @@ -171,7 +358,8 @@ void KernelMainThread() const char *USpace_msg = "Setting up userspace"; for (size_t i = 0; i < strlen(USpace_msg); i++) Display->Print(USpace_msg[i], 0); - Display->SetBuffer(0); + if (!Config.BootAnimation) + Display->SetBuffer(0); Execute::SpawnData ret = {Execute::ExStatus::Unknown, nullptr, nullptr}; Tasking::TCB *ExecuteThread = nullptr; @@ -182,12 +370,14 @@ void KernelMainThread() ExecuteThread->SetPriority(Tasking::Idle); Display->Print('.', 0); - Display->SetBuffer(0); + if (!Config.BootAnimation) + Display->SetBuffer(0); ret = SpawnInit(); Display->Print('.', 0); - Display->SetBuffer(0); + if (!Config.BootAnimation) + Display->SetBuffer(0); if (ret.Status != Execute::ExStatus::OK) { @@ -200,7 +390,8 @@ void KernelMainThread() Display->Print('.', 0); Display->Print('\n', 0); - Display->SetBuffer(0); + if (!Config.BootAnimation) + Display->SetBuffer(0); KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath); TaskManager->GetCurrentThread()->SetPriority(Tasking::Idle); @@ -213,6 +404,7 @@ Exit: KPrint("\eE85230Userspace process exited with code %d", ExitCode); KPrint("Dropping to recovery screen..."); TaskManager->Sleep(2500); + TaskManager->WaitForThread(blaThread); RecoveryScreen = new Recovery::KernelRecovery; } else @@ -224,9 +416,21 @@ Exit: CPU::Halt(true); } -void KernelShutdownThread(bool Reboot) +void __no_stack_protector KernelShutdownThread(bool Reboot) { - BeforeShutdown(); + SmartLock(ShutdownLock); + debug("KernelShutdownThread(%s)", Reboot ? "true" : "false"); + if (Config.BootAnimation && TaskManager) + { + if (RecoveryScreen) + delete RecoveryScreen, RecoveryScreen = nullptr; + + Tasking::TCB *elaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)ExitLogoAnimationThread); + elaThread->Rename("Logo Animation"); + TaskManager->WaitForThread(elaThread); + } + + BeforeShutdown(Reboot); trace("%s...", Reboot ? "Rebooting" : "Shutting down"); if (Reboot) @@ -235,3 +439,6 @@ void KernelShutdownThread(bool Reboot) PowerManager->Shutdown(); CPU::Stop(); } + +void KST_Reboot() { KernelShutdownThread(true); } +void KST_Shutdown() { KernelShutdownThread(false); } diff --git a/Kernel.cpp b/Kernel.cpp index 1d1a29f6..e1b8dc68 100644 --- a/Kernel.cpp +++ b/Kernel.cpp @@ -15,8 +15,6 @@ #include "Core/smbios.hpp" #include "Tests/t.h" -NewLock(ShutdownLock); - bool DebuggerIsAttached = false; #ifdef DEBUG @@ -49,6 +47,7 @@ LockClass mExtTrkLock; * - [ ] Colors in crash screen are not following the kernel color scheme. * - [ ] Find a way to add intrinsics. * - [ ] Rework PSF1 font loader. + * - [ ] The cleanup should be done by a thread (tasking). This is done to avoid a deadlock. * * ISSUES: * - [ ] Kernel stack is smashed when an interrupt occurs. (this bug it occurs when an interrupt like IRQ1 or IRQ12 occurs) @@ -160,14 +159,28 @@ PCI::PCI *PCIManager = nullptr; Tasking::Task *TaskManager = nullptr; Time::time *TimeManager = nullptr; VirtualFileSystem::Virtual *vfs = nullptr; +VirtualFileSystem::Virtual *bootanim_vfs = nullptr; -KernelConfig Config; Time::Clock BootClock; +KernelConfig Config = { + .AllocatorType = Memory::MemoryAllocatorType::XallocV1, + .SchedulerType = 0, + .DriverDirectory = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\0'}, + .InitPath = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'i', 'n', 'i', 't', '\0'}, + .InterruptsOnCrash = true, + .Cores = 0, + .IOAPICInterruptCore = 0, + .UnlockDeadLock = false, + .SIMD = false, + .BootAnimation = false, +}; + extern bool EnableProfiler; // For the Display class. Printing on first buffer as default. -EXTERNC void putchar(char c) { Display->Print(c, 0); } +int PutCharBufferIndex = 0; +EXTERNC void putchar(char c) { Display->Print(c, PutCharBufferIndex); } EXTERNC void KPrint(const char *Format, ...) { @@ -182,7 +195,8 @@ EXTERNC void KPrint(const char *Format, ...) va_end(args); putchar('\n'); - Display->SetBuffer(0); + if (!Config.BootAnimation) + Display->SetBuffer(0); } EXTERNC NIF void Main(BootInfo *Info) @@ -204,7 +218,20 @@ EXTERNC NIF void Main(BootInfo *Info) Interrupts::Initialize(0); KPrint("Reading Kernel Parameters"); - Config = ParseConfig((char *)bInfo->Kernel.CommandLine); + ParseConfig((char *)bInfo->Kernel.CommandLine, &Config); + + if (Config.BootAnimation) + { + Display->CreateBuffer(0, 0, 1); + + Video::ScreenBuffer *buf = Display->GetBuffer(1); + Video::FontInfo fi = Display->GetCurrentFont()->GetInfo(); + Display->SetBufferCursor(1, 0, buf->Height - fi.Height); + PutCharBufferIndex = 1; + printf("Fennix Operating System - %s [\e058C19%s\eFFFFFF]\n", KERNEL_VERSION, GIT_COMMIT_SHORT); + Display->SetBuffer(1); + PutCharBufferIndex = 0; + } KPrint("Initializing CPU Features"); CPU::InitializeFeatures(0); @@ -320,7 +347,30 @@ EXTERNC NIF void Main(BootInfo *Info) KPrint("Initializing Filesystem..."); vfs = new VirtualFileSystem::Virtual; - new VirtualFileSystem::USTAR((uintptr_t)bInfo->Modules[0].Address, vfs); // TODO: Detect initrd + + if (Config.BootAnimation) + bootanim_vfs = new VirtualFileSystem::Virtual; + + for (size_t i = 0; i < MAX_MODULES; i++) + { + if (!bInfo->Modules[i].Address) + continue; + + if (strcmp(bInfo->Modules[i].CommandLine, "initrd") == 0) + { + debug("Found initrd at %p", bInfo->Modules[i].Address); + static char initrd = 0; + if (!initrd++) + new VirtualFileSystem::USTAR((uintptr_t)bInfo->Modules[i].Address, vfs); + } + if (strcmp(bInfo->Modules[i].CommandLine, "bootanim") == 0 && Config.BootAnimation) + { + debug("Found bootanim at %p", bInfo->Modules[i].Address); + static char bootanim = 0; + if (!bootanim++) + new VirtualFileSystem::USTAR((uintptr_t)bInfo->Modules[i].Address, bootanim_vfs); + } + } if (!vfs->PathExists("/system")) vfs->Create("/system", NodeFlags::DIRECTORY); @@ -404,23 +454,41 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info) #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" -EXTERNC __no_stack_protector NIF void BeforeShutdown() +EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot) { - SmartLock(ShutdownLock); /* TODO: Announce shutdown */ trace("\n\n\n#################### SYSTEM SHUTTING DOWN ####################\n\n"); - delete NIManager, NIManager = nullptr; - delete DiskManager, DiskManager = nullptr; - delete DriverManager, DriverManager = nullptr; - TaskManager->SignalShutdown(); - delete TaskManager, TaskManager = nullptr; if (RecoveryScreen) delete RecoveryScreen, RecoveryScreen = nullptr; - delete vfs, vfs = nullptr; - delete TimeManager, TimeManager = nullptr; - delete Display, Display = nullptr; + + if (NIManager) + delete NIManager, NIManager = nullptr; + + if (DiskManager) + delete DiskManager, DiskManager = nullptr; + + if (DriverManager) + delete DriverManager, DriverManager = nullptr; + + if (TaskManager) + { + TaskManager->SignalShutdown(); + delete TaskManager, TaskManager = nullptr; + } + + if (vfs) + delete vfs, vfs = nullptr; + + if (bootanim_vfs) + delete bootanim_vfs, bootanim_vfs = nullptr; + + if (TimeManager) + delete TimeManager, TimeManager = nullptr; + + if (Display) + delete Display, Display = nullptr; // PowerManager should not be called // https://wiki.osdev.org/Calling_Global_Constructors diff --git a/Recovery/RecoveryMain.cpp b/Recovery/RecoveryMain.cpp index e6ee9f78..925decd8 100644 --- a/Recovery/RecoveryMain.cpp +++ b/Recovery/RecoveryMain.cpp @@ -285,17 +285,8 @@ namespace Recovery RecoveryScreen->RecoveryThread(); } - void RebootCommandThread() - { - CriticalSection cs; - PowerManager->Reboot(); - } - - void ShutdownCommandThread() - { - CriticalSection cs; - PowerManager->Shutdown(); - } + void RebootCommandThread() { KST_Reboot(); } + void ShutdownCommandThread() { KST_Shutdown(); } void RebootCommandWrapper() { TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)RebootCommandThread); } void ShutdownCommandWrapper() { TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)ShutdownCommandThread); } @@ -309,7 +300,7 @@ namespace Recovery gui = new GraphicalUserInterface::GUI; - TCB *guiThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)GUIWrapper); + guiThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)GUIWrapper); guiThread->Rename("GUI Thread"); guiThread->SetPriority(Tasking::TaskPriority::Critical); @@ -339,12 +330,16 @@ namespace Recovery wdgDbgWin = new WidgetCollection(DbgWin); Video::Font *NewFont = new Video::Font(&_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_start, &_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_end, Video::FontType::PCScreenFont2); wdgDbgWin->ReplaceFont(NewFont); - TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)RecoveryThreadWrapper)->SetPriority(Tasking::TaskPriority::Idle); + recoveryThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)RecoveryThreadWrapper); + recoveryThread->Rename("Recovery Thread"); + recoveryThread->SetPriority(Tasking::TaskPriority::Idle); } KernelRecovery::~KernelRecovery() { debug("Destructor called"); + TaskManager->KillThread(guiThread, 0); + TaskManager->KillThread(recoveryThread, 0); delete gui, gui = nullptr; } } diff --git a/SystemCalls/Native.cpp b/SystemCalls/Native.cpp index 9b8ec101..9aa14e80 100644 --- a/SystemCalls/Native.cpp +++ b/SystemCalls/Native.cpp @@ -54,7 +54,8 @@ static int sys_print(SyscallsFrame *Frame, char Char, int Index) char ret = Display->Print(Char, Index, true); #ifdef DEBUG - Display->SetBuffer(Index); + if (!Config.BootAnimation && Index != 0) + Display->SetBuffer(Index); #endif UNUSED(Frame); return ret; diff --git a/include/recovery.hpp b/include/recovery.hpp index 6d1e4392..d43d042f 100644 --- a/include/recovery.hpp +++ b/include/recovery.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace Recovery { @@ -10,6 +11,8 @@ namespace Recovery { private: Memory::MemMgr *mem; + Tasking::TCB *guiThread; + Tasking::TCB *recoveryThread; public: void RecoveryThread(); diff --git a/kernel.h b/kernel.h index 0d4972d6..90b6a130 100644 --- a/kernel.h +++ b/kernel.h @@ -38,6 +38,7 @@ extern KernelConfig Config; extern Tasking::Task *TaskManager; extern Time::time *TimeManager; extern VirtualFileSystem::Virtual *vfs; +extern VirtualFileSystem::Virtual *bootanim_vfs; extern Driver::Driver *DriverManager; extern Disk::Manager *DiskManager; extern NetworkInterfaceManager::NetworkInterface *NIManager; @@ -54,10 +55,12 @@ extern VirtualFileSystem::Node *ProcFS; EXTERNC void putchar(char c); EXTERNC void KPrint(const char *format, ...); EXTERNC void Entry(struct BootInfo *Info); -EXTERNC void BeforeShutdown(); +EXTERNC void BeforeShutdown(bool Reboot); EXTERNC void TaskingPanic(); EXTERNC void KernelMainThread(); EXTERNC void KernelShutdownThread(bool Reboot); +EXTERNC void KST_Reboot(); +EXTERNC void KST_Shutdown(); #endif // !__FENNIX_KERNEL_KERNEL_H__