/* 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 "kernel.h" #ifdef DEBUG #include "tests/t.h" #endif #include #include #include #include #include #include #include #include #include #include #include int SpawnNativeInit() { const char *envp[] = { "PATH=/sys/bin:/usr/bin", "LD_LIBRARY_PATH=/sys/lib:/usr/lib", "TERM=tty", "HOME=/home/root", "USER=root", "TZ=UTC", nullptr}; const char *argv[] = {Config.InitPath, nullptr}; return Execute::Spawn(Config.InitPath, argv, envp, nullptr, false, Tasking::Native, true); } int SpawnLinuxInit() { const char *envp[] = { "PATH=/bin:/usr/bin", "LD_LIBRARY_PATH=/lib:/usr/lib", "TERM=tty", "HOME=/root", "USER=root", "TZ=UTC", nullptr}; std::string init = Config.InitPath; std::vector fallbackPaths = { init, "/bin/init", "/sbin/init", "/system/init", "/usr/bin/init", "/boot/init", "/startup/init"}; const char *foundPath = nullptr; Node root = fs->GetRoot(1); for (const std::string &path : fallbackPaths) { const char *str = path.c_str(); if (fs->Lookup(root, str) == false) continue; foundPath = str; break; } if (!foundPath) { error("No valid init found in fallback paths"); return -ENOENT; } const char *argv[] = {foundPath, nullptr}; return Execute::Spawn(foundPath, argv, envp, nullptr, false, Tasking::Linux, true); } int SpawnInit() { if (Config.LinuxSubsystem) return SpawnLinuxInit(); else return SpawnNativeInit(); } void KernelMainThread() { thisThread->SetPriority(Tasking::Critical); #ifdef DEBUG StressKernel(); // TaskManager->CreateThread(thisProcess, Tasking::IP(tasking_test_fb)); // TaskManager->CreateThread(thisProcess, Tasking::IP(tasking_test_mutex)); // ilp; TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr)); TaskManager->CreateThread(thisProcess, Tasking::IP(TaskHeartbeat)); TreeFS(fs->GetRoot(0), 0); coroutineTest(); #endif KPrint("Kernel compiled using GCC %d.%d.%d as of %s %s with Standard C++ %dL", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, __DATE__, __TIME__, __cplusplus); if (IsVirtualizedEnvironment()) KPrint("Running in a virtualized environment"); KPrint("Initializing Driver Manager"); DriverManager = new Driver::Manager; KPrint("Loading Drivers"); DriverManager->PreloadDrivers(); DriverManager->LoadAllDrivers(); KernelConsole::LateInit(); #ifdef DEBUG // TaskManager->CreateThread(thisProcess, // Tasking::IP(KShellThread)) // ->Rename("Kernel Shell"); #endif KPrint("Loading Subsystems"); Subsystem::Linux::InitializeSubSystem(); Subsystem::Windows::InitializeSubSystem(); #ifdef DEBUG __late_playground(); #endif KPrint("Executing %s", Config.InitPath); int ExitCode = -1; Tasking::PCB *initProc; Tasking::TCB *initThread; int tid = SpawnInit(); if (tid < 0) { KPrint("\x1b[1;37;41mFailed to start init program! Error: %s (%d)", strerror(tid), tid); goto Exit; } KPrint("Waiting for init program to start..."); thisThread->SetPriority(Tasking::Idle); initProc = TaskManager->GetProcessByID(tid); initThread = TaskManager->GetThreadByID(tid, initProc); TaskManager->WaitForThread(initThread); if (initThread) ExitCode = initThread->GetExitCode(); else ExitCode = 0xEBAD; Exit: KPrint("\x1b[31mUserspace process exited with code %d (%#x)", ExitCode, ExitCode < 0 ? -ExitCode : ExitCode); KPrint("Dropping to kernel shell"); TaskManager->Sleep(1000); TaskManager->CreateThread(thisProcess, Tasking::IP(KShellThread))->Rename("Kernel Shell"); CPU::Halt(true); } NewLock(ShutdownLock); void __no_stack_protector KernelShutdownThread(bool Reboot) { SmartLock(ShutdownLock); debug("KernelShutdownThread(%s)", Reboot ? "true" : "false"); BeforeShutdown(Reboot); trace("%s...", Reboot ? "Rebooting" : "Shutting down"); KPrint("Waiting for ACPI..."); if (Reboot) PowerManager->Reboot(); else PowerManager->Shutdown(); KPrint("CPU Halted"); CPU::Stop(); } void KST_Reboot() { KernelShutdownThread(true); } void KST_Shutdown() { KernelShutdownThread(false); }