diff options
Diffstat (limited to 'src/kernel/KernelKit')
43 files changed, 3722 insertions, 0 deletions
diff --git a/src/kernel/KernelKit/BinaryMutex.h b/src/kernel/KernelKit/BinaryMutex.h new file mode 100644 index 00000000..5431ab72 --- /dev/null +++ b/src/kernel/KernelKit/BinaryMutex.h @@ -0,0 +1,39 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/Timer.h> +#include <NeKit/Defines.h> + +namespace Kernel { +class USER_PROCESS; + +/// @brief Access control class, which locks a task until one is done. +class BinaryMutex final { + public: + explicit BinaryMutex() = default; + ~BinaryMutex() = default; + + public: + bool IsLocked() const; + bool Unlock() noexcept; + + public: + BOOL WaitForProcess(const UInt32& sec) noexcept; + + public: + bool Lock(USER_PROCESS* process); + bool LockAndWait(USER_PROCESS* process, TimerInterface* timer); + + public: + NE_COPY_DEFAULT(BinaryMutex) + + private: + USER_PROCESS* fLockingProcess{nullptr}; +}; +} // namespace Kernel diff --git a/src/kernel/KernelKit/CodeMgr.h b/src/kernel/KernelKit/CodeMgr.h new file mode 100644 index 00000000..e537b26d --- /dev/null +++ b/src/kernel/KernelKit/CodeMgr.h @@ -0,0 +1,49 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: CodeMgr.h + Purpose: Code Mgr. + + Revision History: + + 30/01/24: Added file (amlel) + 3/8/24: Add UPP struct. + +======================================== */ + +#pragma once + +#include <KernelKit/CoreProcessScheduler.h> +#include <KernelKit/IPEFDylibObject.h> +#include <KernelKit/PE32CodeMgr.h> +#include <KernelKit/PEFCodeMgr.h> + +/// @file CodeMgr.h +/// @brief Code Manager header file. +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +namespace Kernel { +/// @brief Main process entrypoint. +typedef void (*rtl_main_kind)(void); + +/// @brief C++ Constructor entrypoint. +typedef void (*rtl_cxx_ctor_kind)(void); + +/// @brief C++ Destructor entrypoint. +typedef void (*rtl_cxx_dtor_kind)(void); + +/// @brief Executes a new process from a function. Kernel code only. +/// @note This sets up a new stack, anything on the main function that calls the Kernel will not be +/// accessible. +/// @param main the start of the process. +/// @return The team's process id. +BOOL rtl_create_kernel_task(HAL::StackFramePtr main, const KID kid) noexcept; + +/// @brief Executes a new process from a function. User code only. +/// @note This sets up a new stack, anything on the main function that calls the Kernel will not be +/// accessible. +/// @param main the start of the process. +/// @return The team's process id. +ProcessID rtl_create_user_process(rtl_main_kind main, const Char* process_name) noexcept; +} // namespace Kernel diff --git a/src/kernel/KernelKit/CoreProcessScheduler.h b/src/kernel/KernelKit/CoreProcessScheduler.h new file mode 100644 index 00000000..54a0614a --- /dev/null +++ b/src/kernel/KernelKit/CoreProcessScheduler.h @@ -0,0 +1,273 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <NeKit/Defines.h> +#include <NeKit/ErrorOr.h> + +/// @file CoreProcessScheduler.h +/// @brief Core Process Scheduler header file. +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +#define kSchedMinMicroTime (AffinityKind::kStandard) +#define kSchedInvalidPID (-1) +#define kSchedProcessLimitPerTeam (32U) +#define kSchedTeamCount (256U) + +#define kSchedMaxMemoryLimit (gib_cast(128)) /* max physical memory limit */ +#define kSchedMaxStackSz (kib_cast(8)) /* maximum stack size */ + +#define kSchedNameLen (128U) + +EXTERN_C void sched_idle_task(void); + +namespace Kernel { +class USER_PROCESS; +class KERNEL_TASK; +class KernelTaskScheduler; +class UserProcessScheduler; +class UserProcessTeam; + +template <typename T> +struct PROCESS_HEAP_TREE; + +template <typename T> +struct PROCESS_SPECIAL_TREE; + +template <typename T> +struct PROCESS_FILE_TREE; + +enum { + kInvalidTreeKind = 0U, + kRedTreeKind = 100U, + kBlackTreeKind = 101U, + kTreeKindCount = 3U, +}; + +template <typename T> +struct PROCESS_HEAP_TREE { + static constexpr auto kHeap = true; + static constexpr auto kFile = false; + static constexpr auto kSpecial = false; + + T Entry{nullptr}; + SizeT EntrySize{0UL}; + SizeT EntryPad{0UL}; + + UInt32 Color{kBlackTreeKind}; + + struct PROCESS_HEAP_TREE<T>* Parent { + nullptr + }; + struct PROCESS_HEAP_TREE<T>* Child { + nullptr + }; + + struct PROCESS_HEAP_TREE<T>* Prev { + nullptr + }; + struct PROCESS_HEAP_TREE<T>* Next { + nullptr + }; +}; + +template <typename T> +struct PROCESS_FILE_TREE { + static constexpr auto kHeap = false; + static constexpr auto kFile = true; + static constexpr auto kSpecial = false; + + T Entry{nullptr}; + SizeT EntrySize{0UL}; + SizeT EntryPad{0UL}; + + UInt32 Color{kBlackTreeKind}; + + struct PROCESS_FILE_TREE<T>* Parent { + nullptr + }; + + struct PROCESS_FILE_TREE<T>* Child { + nullptr + }; + + struct PROCESS_FILE_TREE<T>* Prev { + nullptr + }; + + struct PROCESS_FILE_TREE<T>* Next { + nullptr + }; +}; + +using ProcessCtx = UInt32; + +template <typename T> +struct PROCESS_SPECIAL_TREE { + static constexpr auto kHeap = false; + static constexpr auto kFile = false; + static constexpr auto kSpecial = true; + + T Entry{nullptr}; + SizeT EntrySize{0UL}; + SizeT EntryPad{0UL}; + + /// @brief a context is where the resource comes from. + ProcessCtx EntryContext{0UL}; // could be a socket, printer, device... + + UInt32 Color{kBlackTreeKind}; + + struct PROCESS_SPECIAL_TREE<T>* Parent { + nullptr + }; + + struct PROCESS_SPECIAL_TREE<T>* Child { + nullptr + }; + + struct PROCESS_SPECIAL_TREE<T>* Prev { + nullptr + }; + + struct PROCESS_SPECIAL_TREE<T>* Next { + nullptr + }; +}; + +/***********************************************************************************/ +/// @brief Subsystem enum type. +/***********************************************************************************/ + +enum class ProcessSubsystem : Int32 { + kProcessSubsystemSecurity = 100, + kProcessSubsystemUser, + kProcessSubsystemService, + kProcessSubsystemDriver, + kProcessSubsystemKernel, + kProcessSubsystemCount = kProcessSubsystemKernel - kProcessSubsystemSecurity + 1, + kProcessSubsystemInvalid = 0xFFFFFFF, +}; + +/***********************************************************************************/ +//! @brief Local Process status enum. +/***********************************************************************************/ +enum class ProcessStatusKind : Int32 { + kInvalid = 0, + kStarting = 100, + kRunning, + kKilled, + kFrozen, + kFinished, + kCount = kFinished - kStarting + 1, +}; + +/***********************************************************************************/ +//! @brief Affinity is the amount of nano-seconds this process is going to run. +/***********************************************************************************/ +enum class AffinityKind : Int32 { + kInvalid = 0, + kRealTime = 100, + kVeryHigh = 150, + kHigh = 200, + kStandard = 1000, + kLowUsage = 1500, + kVeryLowUsage = 2000, +}; + +/***********************************************************************************/ +//! Operators for AffinityKind +/***********************************************************************************/ + +inline bool operator<(AffinityKind lhs, AffinityKind rhs) { + Int32 lhs_int = static_cast<Int32>(lhs); + Int32 rhs_int = static_cast<Int32>(rhs); + + return lhs_int < rhs_int; +} + +inline bool operator>(AffinityKind lhs, AffinityKind rhs) { + Int32 lhs_int = static_cast<Int32>(lhs); + Int32 rhs_int = static_cast<Int32>(rhs); + + return lhs_int > rhs_int; +} + +inline bool operator<=(AffinityKind lhs, AffinityKind rhs) { + Int32 lhs_int = static_cast<Int>(lhs); + Int32 rhs_int = static_cast<Int32>(rhs); + + return lhs_int <= rhs_int; +} + +inline bool operator>=(AffinityKind lhs, AffinityKind rhs) { + Int32 lhs_int = static_cast<Int32>(lhs); + Int32 rhs_int = static_cast<Int32>(rhs); + + return lhs_int >= rhs_int; +} + +using PTime = UInt64; +using ProcessTime = PTime; + +/***********************************************************************************/ +//! @brief Local Process Identifier type. +/***********************************************************************************/ +using ProcessID = Int64; + +/***********************************************************************************/ +/// @note For User manager, tells where we run the code. +/***********************************************************************************/ +enum class ProcessLevelRing : Int32 { + kRingStdUser = 1, + kRingSuperUser = 2, + kRingGuestUser = 5, + kRingCount = 3, +}; + +/***********************************************************************************/ +/// @brief Helper type to describe a code image. +/***********************************************************************************/ +using ImagePtr = VoidPtr; + +/***********************************************************************************/ +/// @brief Helper class to contain a process's image and blob. +/***********************************************************************************/ +struct ProcessImage final { + explicit ProcessImage() = default; + + private: + friend USER_PROCESS; + friend KERNEL_TASK; + + friend UserProcessScheduler; + friend KernelTaskScheduler; + + ImagePtr fCode{}; + ImagePtr fBlob{}; + + public: + Bool HasCode() const { return this->fCode != nullptr; } + + Bool HasImage() const { return this->fBlob != nullptr; } + + ErrorOr<ImagePtr> LeakImage() { + if (this->fCode) { + return ErrorOr<ImagePtr>{this->fCode}; + } + + return ErrorOr<ImagePtr>{kErrorInvalidData}; + } + + ErrorOr<ImagePtr> LeakBlob() { + if (this->fBlob) { + return ErrorOr<ImagePtr>{this->fBlob}; + } + + return ErrorOr<ImagePtr>{kErrorInvalidData}; + } +}; +} // namespace Kernel diff --git a/src/kernel/KernelKit/DebugOutput.h b/src/kernel/KernelKit/DebugOutput.h new file mode 100644 index 00000000..3f9b5125 --- /dev/null +++ b/src/kernel/KernelKit/DebugOutput.h @@ -0,0 +1,207 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/DeviceMgr.h> +#include <NeKit/OwnPtr.h> +#include <NeKit/Stream.h> +#include <NeKit/Utils.h> + +namespace Kernel { +class TerminalDevice; +class DTraceDevice; +class NeTraceDevice; +class Utf8TerminalDevice; + +inline TerminalDevice end_line(); +inline TerminalDevice number(const Long& x); +inline TerminalDevice hex_number(const Long& x); + +// @brief Emulates a VT100 terminal. +class TerminalDevice final NE_DEVICE<const Char*> { + public: + TerminalDevice(void (*print)(DeviceInterface*, const Char*), + void (*gets)(DeviceInterface*, const Char*)) + : DeviceInterface<const Char*>(print, gets) {} + + ~TerminalDevice() override; + + /// @brief returns device name (terminal name) + /// @return string type (const Char*) + const Char* Name() const override { return ("TerminalDevice"); } + + NE_COPY_DEFAULT(TerminalDevice) + + STATIC TerminalDevice The() noexcept; +}; + +class Utf8TerminalDevice final NE_DEVICE<const Utf8Char*> { + public: + Utf8TerminalDevice(void (*print)(DeviceInterface*, const Utf8Char*), + void (*gets)(DeviceInterface*, const Utf8Char*)) + : DeviceInterface<const Utf8Char*>(print, gets) {} + + ~Utf8TerminalDevice() override; + + /// @brief returns device name (terminal name) + /// @return string type (const Char*) + const Char* Name() const override { return ("Utf8TerminalDevice"); } + + NE_COPY_DEFAULT(Utf8TerminalDevice) + + STATIC Utf8TerminalDevice The() noexcept; +}; + +inline TerminalDevice end_line() { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\r"); + return self; +} + +inline Utf8TerminalDevice utf_end_line() { + Utf8TerminalDevice self = Utf8TerminalDevice::The(); + + self.operator<<(u8"\r"); + return self; +} + +inline TerminalDevice carriage_return() { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\r"); + return self; +} + +inline TerminalDevice tabulate() { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\t"); + return self; +} + +/// @brief emulate a terminal bell, like the VT100 does. +inline TerminalDevice bell() { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\a"); + return self; +} + +namespace Detail { + inline TerminalDevice _write_number(const Long& x, TerminalDevice& term) { + UInt64 y = (x > 0 ? x : -x) / 10; + UInt64 h = (x > 0 ? x : -x) % 10; + + if (y) _write_number(y, term); + + /* fail if the number is not base-10 */ + if (h > 10) { + _write_number('?', term); + return term; + } + + if (y == ~0UL) y = -y; + + const Char kNumbers[11] = "0123456789"; + + Char buf[2]; + buf[0] = kNumbers[h]; + buf[1] = 0; + + term.operator<<(buf); + return term; + } + + inline TerminalDevice _write_number_hex(const Long& x, TerminalDevice& term) { + UInt64 y = (x > 0 ? x : -x) / 16; + UInt64 h = (x > 0 ? x : -x) % 16; + + if (y) _write_number_hex(y, term); + + /* fail if the hex number is not base-16 */ + if (h > 16) { + _write_number_hex('?', term); + return term; + } + + if (y == ~0UL) y = -y; + + const Char kNumbers[17] = "0123456789ABCDEF"; + + Char buf[2]; + buf[0] = kNumbers[h]; + buf[1] = 0; + + term.operator<<(buf); + return term; + } +} // namespace Detail + +inline TerminalDevice hex_number(const Long& x) { + TerminalDevice self = TerminalDevice::The(); + + self << "0x"; + Detail::_write_number_hex(x, self); + + return self; +} + +inline TerminalDevice number(const Long& x) { + TerminalDevice self = TerminalDevice::The(); + + Detail::_write_number(x, self); + + return self; +} + +inline TerminalDevice get_console_in(Char* buf) { + TerminalDevice self = TerminalDevice::The(); + + self >> buf; + + return self; +} + +inline constexpr auto kDebugPort = 51820; +inline constexpr auto kDebugMagic = "VMK1.0.0;"; +inline constexpr auto kDebugVersion = 0x0100; + +inline constexpr SizeT kDebugCmdLen = 256U; + +typedef Char rt_debug_cmd[kDebugCmdLen]; + +inline TerminalDevice& operator<<(TerminalDevice& src, const Long& num) { + src = number(num); + return src; +} +} // namespace Kernel + +#ifdef kout +#undef kout +#endif // ifdef kout + +#define kout TerminalDevice::The() + +#ifdef kendl +#undef kendl +#endif // ifdef kendl + +#define kendl end_line() + +#ifdef kout8 +#undef kout8 +#endif // ifdef kout8 + +#define kout8 Utf8TerminalDevice::The() + +#ifdef kendl8 +#undef kendl8 +#endif // ifdef kendl8 + +#define kendl8 utf_end_line() diff --git a/src/kernel/KernelKit/Defines.h b/src/kernel/KernelKit/Defines.h new file mode 100644 index 00000000..e88441d2 --- /dev/null +++ b/src/kernel/KernelKit/Defines.h @@ -0,0 +1,19 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <NeKit/Defines.h> + +#define KERNELKIT_VERSION "0.0.1-kernelkit" +#define KERNELKIT_VERSION_BCD 0x0001 + +namespace Kernel { +class UserProcessScheduler; +class IDylibObject; +class USER_PROCESS; +class KERNEL_TASK; +} // namespace Kernel
\ No newline at end of file diff --git a/src/kernel/KernelKit/DeviceMgr.h b/src/kernel/KernelKit/DeviceMgr.h new file mode 100644 index 00000000..1dbad161 --- /dev/null +++ b/src/kernel/KernelKit/DeviceMgr.h @@ -0,0 +1,129 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +/* ======================================== + + Revision History: + + 31/01/24: Add kDeviceCnt (amlel) + 15/11/24: Add NE_DEVICE macro, to inherit from device object. + + ======================================== */ + +#pragma once + +/* @note Device Mgr. */ +/* @file KernelKit/DeviceMgr.h */ +/* @brief Device abstraction and I/O buffer. */ + +#include <NeKit/ErrorOr.h> +#include <NeKit/Ref.h> + +#define kDeviceMgrRootDirPath "/devices/" + +#define NE_DEVICE : public ::Kernel::DeviceInterface + +// Last Rev: Wed, May 27, 2025 6:22 PM + +namespace Kernel { +template <typename T> +class DeviceInterface; + +template <typename T> +class IOBuf; + +/***********************************************************************************/ +/// @brief Device contract interface, represents an HW device. +/***********************************************************************************/ +template <typename T> +class DeviceInterface { + public: + DeviceInterface() = default; + + explicit DeviceInterface(void (*Out)(DeviceInterface<T>*, T), void (*In)(DeviceInterface<T>*, T)) + : fOut(Out), fIn(In) {} + + virtual ~DeviceInterface() = default; + + public: + DeviceInterface& operator=(const DeviceInterface<T>&) = default; + DeviceInterface(const DeviceInterface<T>&) = default; + + public: + virtual DeviceInterface<T>& operator<<(T Data) { + fOut(this, Data); + return *this; + } + + virtual DeviceInterface<T>& operator>>(T Data) { + fIn(this, Data); + return *this; + } + + virtual const char* Name() const { return "/devices/null"; } + + operator bool() { return fOut && fIn; } + + Bool operator!() { return !fOut || !fIn; } + + protected: + Void (*fOut)(DeviceInterface<T>*, T Data) = {nullptr}; + Void (*fIn)(DeviceInterface<T>*, T Data) = {nullptr}; +}; + +/// +/// @brief Input Output abstract class. +/// Used mainly to communicate between OS to hardware. +/// +template <typename T> +class IOBuf final { + public: + explicit IOBuf(T dma_addr) : fData(dma_addr) { + // At least pass something valid when instancating this struct. + MUST_PASS(fData); + } + + IOBuf& operator=(const IOBuf<T>&) = default; + IOBuf(const IOBuf<T>&) = default; + + ~IOBuf() = default; + + public: + template <typename R> + R operator->() const { + return fData; + } + + template <typename R> + R& operator[](Size index) const { + return fData[index]; + } + + private: + T fData; +}; + +///! @brief Device enum types. +enum { + kDeviceTypeInvalid = 0, + kDeviceTypeIDE = 100, + kDeviceTypeEthernet, + kDeviceTypeWiFi, + kDeviceTypeFW, + kDeviceTypeBT, + kDeviceTypeRS232, + kDeviceTypeSCSI, + kDeviceTypeAHCI, + kDeviceTypeMBCI, + kDeviceTypeATA, + kDeviceTypeUSB, + kDeviceTypeAPM, // Adv. Pwr. Mgmt. + kDeviceTypePCI, + kDeviceTypeVGA, + kDeviceTypeGPU, + kDeviceTypeCount, +}; +} // namespace Kernel diff --git a/src/kernel/KernelKit/DriveMgr.h b/src/kernel/KernelKit/DriveMgr.h new file mode 100644 index 00000000..daf93b89 --- /dev/null +++ b/src/kernel/KernelKit/DriveMgr.h @@ -0,0 +1,175 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef INC_DRIVE_MANAGER_H +#define INC_DRIVE_MANAGER_H + +/// @file DriveMgr.h +/// @brief Drive Manager. +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/DebugOutput.h> +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/KPC.h> +#include <KernelKit/ProcessScheduler.h> +#include <NeKit/Defines.h> +#include <NeKit/KString.h> +#include <NeKit/Ref.h> + +#define kDriveMaxCount (4U) +#define kDriveSectorSz (512U) +#define kDriveInvalidID (-1) +#define kDriveNameLen (32) + +#define drv_sector_cnt(SIZE, SECTOR_SZ) (((SIZE) + (SECTOR_SZ)) / (SECTOR_SZ)) + +#define kDriveHiddenPrefix '~' + +namespace Kernel { +enum { + kInvalidDrive = -1, + + /// Storage types, combine with flags. + kBlockDevice = 0xAD, + kMassStorageDrive = 0xDA, + kFloppyDrive = 0xCD, + kOpticalDrive = 0xDC, // CD-ROM/DVD-ROM/Blu-Ray + kTapeDrive = 0xD7, + + /// Storage flags, combine with types. + kReadOnlyDrive = 0x10, // Read only drive + kEPMDrive = 0x11, // Explicit Partition Map. + kVEPMDrive = 0x12, // ESP w/ EPM partition. + kMBRDrive = 0x13, // PC classic partition scheme + kGPTDrive = 0x14, // PC new partition scheme + kUnformattedDrive = 0x15, + kStorageCount = 9, +}; + +/// @brief Media drive trait type. +struct DriveTrait final { + Char fName[kDriveNameLen] = "/media/null"; // /System, /boot, //./Devices/USB... + UInt32 fKind{}; // fMassStorage, fFloppy, fOpticalDrive. + UInt32 fFlags{}; // fReadOnly, fEPMDrive... + + /// @brief Packet drive (StorageKit compilant.) + struct DrivePacket final { + VoidPtr fPacketContent{nullptr}; //! packet body. + Char fPacketMime[kDriveNameLen] = "*/*"; //! identify what we're sending. + SizeT fPacketSize{0UL}; //! packet size + UInt32 fPacketCRC32{0UL}; //! sanity crc, in case if good is set to false + Boolean fPacketGood{YES}; + Lba fPacketLba{0UL}; + Boolean fPacketReadOnly{NO}; + } fPacket; + + Lba fLbaStart{0}, fLbaEnd{0}; + SizeT fSectorSz{kDriveSectorSz}; + + Void (*fInput)(DrivePacket& packet){nullptr}; + Void (*fOutput)(DrivePacket& packet){nullptr}; + Void (*fVerify)(DrivePacket& packet){nullptr}; + Void (*fInit)(DrivePacket& packet){nullptr}; + const Char* (*fProtocol)(Void){nullptr}; +}; + +namespace Probe { + Void io_detect_drive(DriveTrait& trait); +} + +///! drive as a device. +typedef DriveTrait* DriveTraitPtr; + +/** + * @brief Mounted drives interface. + * @note This class has all of it's drive set to nullptr, allocate them using + * GetAddressOf(index). + */ +class IMountpoint final { + public: + explicit IMountpoint() = default; + ~IMountpoint() = default; + + NE_COPY_DEFAULT(IMountpoint) + + public: + DriveTrait& A() { return mA; } + + DriveTrait& B() { return mB; } + + DriveTrait& C() { return mC; } + + DriveTrait& D() { return mD; } + + enum { + kDriveIndexA = 0, + kDriveIndexB, + kDriveIndexC, + kDriveIndexD, + kDriveIndexInvalid, + }; + + DriveTraitPtr GetAddressOf(const Int32& index) { + err_local_get() = kErrorSuccess; + + switch (index) { + case kDriveIndexA: + return &mA; + case kDriveIndexB: + return &mB; + case kDriveIndexC: + return &mC; + case kDriveIndexD: + return &mD; + default: { + err_local_get() = kErrorNoSuchDisk; + kout << "No such disc letter.\n"; + + break; + } + } + + return nullptr; + } + + private: + DriveTrait mA, mB, mC, mD; +}; + +/// @brief Unimplemented drive. +/// @param pckt the packet to read. +/// @return +Void io_drv_unimplemented(DriveTrait::DrivePacket* pckt) noexcept; + +/// @brief Gets the drive kind (ATA, SCSI, AHCI...) +/// @param void none. +/// @return the drive kind (ATA, Flash, NVM) +const Char* io_drv_kind(Void); + +/// @brief Makes a new drive. +/// @return the new drive as a trait. +DriveTrait io_construct_blank_drive(Void) noexcept; + +/// @brief Fetches the main drive. +/// @param trait the new drive as a trait. +Void io_construct_main_drive(DriveTrait& trait) noexcept; + +/// @brief Fetches the main drive. +/// @return the new drive as a trait. +/// @deprecated use io_construct_main_drive(DriveTrait& trait) instead. +DriveTrait io_construct_main_drive(Void) noexcept; + +namespace Detect { + Void io_detect_drive(DriveTrait& trait); +} + +Void io_drv_input(DriveTrait::DrivePacket pckt); + +Void io_drv_output(DriveTrait::DrivePacket pckt); +} // namespace Kernel + +#endif /* ifndef INC_DRIVE_MANAGER_H */ diff --git a/src/kernel/KernelKit/FileMgr.h b/src/kernel/KernelKit/FileMgr.h new file mode 100644 index 00000000..93d5f580 --- /dev/null +++ b/src/kernel/KernelKit/FileMgr.h @@ -0,0 +1,445 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss , licensed under the Apache 2.0 license. + + File: FileMgr.h + Purpose: Kernel file manager. + Author: Amlal El Mahrouss (amlal@nekernel.org) + +======================================== */ + +/* ======================================== + + Revision History: + + 31/01/24: Update documentation (amlel) + 05/07/24: NeFS support, and fork support, updated constants and specs + as well. + 18/01/25: Patches to FileStream class. + + ======================================== */ + +#ifndef INC_FILEMGR_H +#define INC_FILEMGR_H + +/// @file FileMgr.h +/// @brief File Manager System. +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +//! Include filesystems that NeKernel supports. +#include <FSKit/Ext2+IFS.h> +#include <FSKit/NeFS.h> +#include <FSKit/OpenHeFS.h> + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/DebugOutput.h> +#include <KernelKit/HeapMgr.h> +#include <KernelKit/KPC.h> +#include <NeKit/ErrorOr.h> +#include <NeKit/Ref.h> +#include <NeKit/Stream.h> +#include <hint/CompilerHint.h> + +/// @brief Filesystem manager, abstraction over mounted filesystem. +/// Works like an VFS (Virtual File System) or IFS subsystem on NT/OS 2. + +#define kRestrictR "r" +#define kRestrictRB "rb" +#define kRestrictW "w" +#define kRestrictWR "rw" +#define kRestrictWRB "rwb" + +#define kRestrictMax (5U) + +#define rtl_node_cast(PTR) reinterpret_cast<Kernel::NodePtr>(PTR) + +#define kFileMimeGeneric "ne-application-kind/all" + +/** @brief invalid position. (n-pos) */ +#define kFileMgrNPos (~0UL) + +namespace Kernel { +enum { + kFileIOInvalid = 0, + kFileWriteAll = 100, + kFileReadAll = 101, + kFileReadChunk = 102, + kFileWriteChunk = 103, + // File flags (HFS+, NeFS specific) + kFileFlagRsrc = 104, + kFileFlagData = 105, + kFileIOCnt = (kFileFlagData - kFileWriteAll) + 1, +}; + +using NodePtr = VoidPtr; + +/** +@brief Filesystem Mgr Interface class +@brief Used to provide common I/O for a specific filesystem. +*/ +class IFilesystemMgr { + public: + explicit IFilesystemMgr() = default; + virtual ~IFilesystemMgr() = default; + + public: + NE_COPY_DEFAULT(IFilesystemMgr) + + public: + /// @brief Mounts a new filesystem into an active state. + /// @param interface the filesystem interface + /// @return + static bool Mount(IFilesystemMgr* interface); + + /// @brief Unmounts the active filesystem + /// @return + static IFilesystemMgr* Unmount(); + + /// @brief Getter, gets the active filesystem. + /// @return + static IFilesystemMgr* GetMounted(); + + public: + virtual NodePtr Create(_Input const Char* path) = 0; + virtual NodePtr CreateAlias(_Input const Char* path) = 0; + virtual NodePtr CreateDirectory(_Input const Char* path) = 0; + virtual NodePtr CreateSwapFile(const Char* path) = 0; + + public: + virtual bool Remove(_Input const Char* path) = 0; + + public: + virtual NodePtr Open(_Input const Char* path, _Input const Char* r) = 0; + + public: + virtual Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT size) = 0; + + virtual _Output VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) = 0; + + virtual Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, + _Input Int32 flags, _Input SizeT size) = 0; + + virtual _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags, + _Input SizeT sz) = 0; + + public: + virtual bool Seek(_Input NodePtr node, _Input SizeT off) = 0; + + public: + virtual SizeT Tell(_Input NodePtr node) = 0; + virtual bool Rewind(_Input NodePtr node) = 0; +}; + +#ifdef __FSKIT_INCLUDES_NEFS__ +/** + * @brief Based of IFilesystemMgr, takes care of managing NeFS + * disks. + */ +class NeFileSystemMgr final : public IFilesystemMgr { + public: + explicit NeFileSystemMgr(); + ~NeFileSystemMgr() override; + + public: + NE_COPY_DEFAULT(NeFileSystemMgr) + + public: + NodePtr Create(const Char* path) override; + NodePtr CreateAlias(const Char* path) override; + NodePtr CreateDirectory(const Char* path) override; + NodePtr CreateSwapFile(const Char* path) override; + + public: + bool Remove(_Input const Char* path) override; + NodePtr Open(_Input const Char* path, _Input const Char* r) override; + Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT sz) override; + VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) override; + bool Seek(_Input NodePtr node, _Input SizeT off) override; + SizeT Tell(_Input NodePtr node) override; + bool Rewind(_Input NodePtr node) override; + + Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT size) override; + + _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags, + _Input SizeT sz) override; + + public: + /// @brief Get NeFS parser class. + /// @return The filesystem parser class. + NeFileSystemParser* GetParser() noexcept; + + private: + NeFileSystemParser* mParser{nullptr}; +}; + +#endif // ifdef __FSKIT_INCLUDES_NEFS__ + +#ifdef __FSKIT_INCLUDES_EXT2__ +/** + * @brief Based of IFilesystemMgr, takes care of managing NeFS + * disks. + */ +class Ext2FileSystemMgr final : public IFilesystemMgr { + public: + explicit Ext2FileSystemMgr(); + ~Ext2FileSystemMgr() override; + + public: + NE_COPY_DEFAULT(Ext2FileSystemMgr) + + public: + NodePtr Create(const Char* path) override; + NodePtr CreateAlias(const Char* path) override; + NodePtr CreateDirectory(const Char* path) override; + NodePtr CreateSwapFile(const Char* path) override; + + public: + bool Remove(_Input const Char* path) override; + NodePtr Open(_Input const Char* path, _Input const Char* r) override; + Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT sz) override; + VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) override; + bool Seek(_Input NodePtr node, _Input SizeT off) override; + SizeT Tell(_Input NodePtr node) override; + bool Rewind(_Input NodePtr node) override; + + Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT size) override; + + _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags, + _Input SizeT sz) override; + + public: + /// @brief Get NeFS parser class. + /// @return The filesystem parser class. + Ext2FileSystemParser* GetParser() noexcept; + + private: + Ext2FileSystemParser* mParser{nullptr}; +}; + +#endif // ifdef __FSKIT_INCLUDES_EXT2__ + +#ifdef __FSKIT_INCLUDES_OPENHEFS__ +/** + * @brief Based of IFilesystemMgr, takes care of managing NeFS + * disks. + */ +class HeFileSystemMgr final : public IFilesystemMgr { + public: + explicit HeFileSystemMgr(); + ~HeFileSystemMgr() override; + + public: + NE_COPY_DEFAULT(HeFileSystemMgr) + + public: + NodePtr Create(const Char* path) override; + NodePtr CreateAlias(const Char* path) override; + NodePtr CreateDirectory(const Char* path) override; + NodePtr CreateSwapFile(const Char* path) override; + + public: + bool Remove(_Input const Char* path) override; + NodePtr Open(_Input const Char* path, _Input const Char* r) override; + Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT sz) override; + VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) override; + bool Seek(_Input NodePtr node, _Input SizeT off) override; + SizeT Tell(_Input NodePtr node) override; + bool Rewind(_Input NodePtr node) override; + + Void Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT size) override; + + _Output VoidPtr Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags, + _Input SizeT sz) override; + + public: + /// @brief Get NeFS parser class. + /// @return The filesystem parser class. + HeFileSystemParser* GetParser() noexcept; + + private: + HeFileSystemParser* mParser{nullptr}; +}; + +#endif // ifdef __FSKIT_INCLUDES_OPENHEFS__ + +/** + * FileStream class. + * @tparam Encoding file encoding (char, wchar_t...) + * @tparam FSClass Filesystem contract who takes care of it. + */ +template <typename Encoding = Char, typename FSClass = IFilesystemMgr> +class FileStream final { + public: + explicit FileStream(const Encoding* path, const Encoding* restrict_type); + ~FileStream(); + + public: + FileStream& operator=(const FileStream&); + FileStream(const FileStream&); + + public: + ErrorOr<Int64> Write(SizeT offset, const VoidPtr data, SizeT len) noexcept { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictWrite && + this->fFileRestrict != kFileMgrRestrictWriteBinary) + return ErrorOr<Int64>(kErrorInvalidData); + + if (data == nullptr) return ErrorOr<Int64>(kErrorInvalidData); + + auto man = FSClass::GetMounted(); + + if (man) { + man->Write(offset, fFile, data, len); + return ErrorOr<Int64>(kErrorSuccess); + } + + return ErrorOr<Int64>(kErrorInvalidData); + } + + ErrorOr<Int64> Write(const Char* name, const VoidPtr data, SizeT len) noexcept { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictWrite && + this->fFileRestrict != kFileMgrRestrictWriteBinary) + return ErrorOr<Int64>(kErrorInvalidData); + + if (data == nullptr) return ErrorOr<Int64>(kErrorInvalidData); + + auto man = FSClass::GetMounted(); + + if (man) { + man->Write(name, fFile, data, 0, len); + return ErrorOr<Int64>(kErrorSuccess); + } + + return ErrorOr<Int64>(kErrorInvalidData); + } + + VoidPtr Read(const Char* name, SizeT sz) noexcept { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictRead && + this->fFileRestrict != kFileMgrRestrictReadBinary) + return nullptr; + + auto man = FSClass::GetMounted(); + + if (man) { + VoidPtr ret = man->Read(name, fFile, kFileReadAll, sz); + return ret; + } + + return nullptr; + } + + VoidPtr Read(SizeT offset, SizeT sz) { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictRead && + this->fFileRestrict != kFileMgrRestrictReadBinary) + return nullptr; + + auto man = FSClass::GetMounted(); + + if (man) { + man->Seek(fFile, offset); + auto ret = man->Read(fFile, kFileReadChunk, sz); + + return ret; + } + + return nullptr; + } + + public: + /// @brief Leak node pointer. + /// @return The node pointer. + NodePtr Leak() { return fFile; } + + /// @brief Leak MIME. + /// @return The MIME. + Char* MIME() noexcept { return const_cast<Char*>(fMime); } + + enum { + kFileMgrRestrictRead = 100, + kFileMgrRestrictReadBinary, + kFileMgrRestrictWrite, + kFileMgrRestrictWriteBinary, + kFileMgrRestrictReadWrite, + kFileMgrRestrictReadWriteBinary, + }; + + private: + NodePtr fFile{nullptr}; + Int32 fFileRestrict{kFileMgrRestrictReadBinary}; + const Char* fMime{kFileMimeGeneric}; +}; + +using FileStreamASCII = FileStream<Char>; +using FileStreamUTF8 = FileStream<Utf8Char>; +using FileStreamUTF16 = FileStream<WideChar>; + +typedef UInt64 CursorType; + +inline STATIC const auto kRestrictStrLen = 8U; + +/// @brief restrict information about the file descriptor. +struct FILEMGR_RESTRICT final { + Char fRestrict[kRestrictStrLen]; + Int32 fMappedTo; +}; + +/// @brief constructor +template <typename Encoding, typename Class> +inline FileStream<Encoding, Class>::FileStream(const Encoding* path, const Encoding* restrict_type) + : fFile(Class::GetMounted()->Open(path, restrict_type)) { + SizeT kRestrictCount = kRestrictMax; + const FILEMGR_RESTRICT kRestrictList[] = {{ + .fRestrict = kRestrictR, + .fMappedTo = kFileMgrRestrictRead, + }, + { + .fRestrict = kRestrictRB, + .fMappedTo = kFileMgrRestrictReadBinary, + }, + { + .fRestrict = kRestrictWRB, + .fMappedTo = kFileMgrRestrictReadWriteBinary, + }, + { + .fRestrict = kRestrictW, + .fMappedTo = kFileMgrRestrictWrite, + }, + { + .fRestrict = kRestrictWR, + .fMappedTo = kFileMgrRestrictReadWrite, + }}; + + for (SizeT index = 0; index < kRestrictCount; ++index) { + if (rt_string_cmp(restrict_type, kRestrictList[index].fRestrict, + rt_string_len(kRestrictList[index].fRestrict)) == 0) { + fFileRestrict = kRestrictList[index].fMappedTo; + break; + } + } + + kout << "FileMgr: Open file at: " << path << ".\r"; +} + +/// @brief destructor of the file stream. +template <typename Encoding, typename Class> +inline FileStream<Encoding, Class>::~FileStream() { + mm_free_ptr(fFile); + fFile = nullptr; +} +} // namespace Kernel + +#endif // ifndef INC_FILEMGR_H diff --git a/src/kernel/KernelKit/HardwareThreadScheduler.h b/src/kernel/KernelKit/HardwareThreadScheduler.h new file mode 100644 index 00000000..36a870ba --- /dev/null +++ b/src/kernel/KernelKit/HardwareThreadScheduler.h @@ -0,0 +1,135 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef __INC_MP_MANAGER_H__ +#define __INC_MP_MANAGER_H__ + +#include <ArchKit/ArchKit.h> +#include <CompilerKit/CompilerKit.h> +#include <NeKit/Ref.h> + +/// @note Last Rev Sun 28 Jul CET 2024 +/// @note Last Rev Thu, Aug 1, 2024 9:07:38 AM + +#define kMaxAPInsideSched (4U) + +namespace Kernel { +class HardwareThread; +class HardwareThreadScheduler; + +using ThreadID = UInt32; + +enum ThreadKind { + kAPInvalid = 0, + kAPSystemReserved = 100, // System reserved thread, well user can't use it + kAPStandard, // user thread, cannot be used by Kernel + kAPRealTime, // fallback thread, cannot be used by user if not clear or + // used by Kernel. + kAPBoot, // The core we booted from, the mama. + kAPCount, +}; + +typedef enum ThreadKind ThreadKind; +typedef ThreadID ThreadID; + +/***********************************************************************************/ +/// +/// \name HardwareThread +/// \brief Abstraction over the CPU's core, used to run processes or threads. +/// +/***********************************************************************************/ + +class HardwareThread final { + public: + explicit HardwareThread(); + ~HardwareThread(); + + public: + NE_COPY_DEFAULT(HardwareThread) + + public: + operator bool(); + + public: + void Wake(const BOOL wakeup = false) noexcept; + void Busy(const BOOL busy = false) noexcept; + + public: + BOOL Switch(HAL::StackFramePtr frame); + BOOL IsWakeup() noexcept; + + public: + HAL::StackFramePtr StackFrame() noexcept; + ThreadKind& Kind() noexcept; + BOOL IsBusy() noexcept; + ThreadID& ID() noexcept; + + private: + HAL::StackFramePtr fStack{nullptr}; + ThreadKind fKind{ThreadKind::kAPStandard}; + ThreadID fID{0}; + Bool fWakeup{NO}; + Bool fBusy{NO}; + UInt64 fPTime{0}; + + private: + friend class HardwareThreadScheduler; + friend class UserProcessHelper; +}; + +/// +/// \name HardwareThreadScheduler +/// \brief Class to manage the thread scheduling. +/// + +class HardwareThreadScheduler final : public ISchedulable { + private: + friend class UserProcessHelper; + + public: + explicit HardwareThreadScheduler(); + ~HardwareThreadScheduler(); + NE_COPY_DEFAULT(HardwareThreadScheduler) + + public: + HAL::StackFramePtr Leak() noexcept; + + public: + Ref<HardwareThread*> operator[](SizeT idx); + bool operator!() noexcept; + operator bool() noexcept; + + Bool IsUser() override { return Yes; } + + Bool IsKernel() override { return No; } + + Bool HasMP() override { return kHandoverHeader->f_HardwareTables.f_MultiProcessingEnabled; } + + public: + /// @brief Shared instance of the MP Mgr. + /// @return the reference to the mp manager class. + STATIC HardwareThreadScheduler& The(); + + public: + /// @brief Returns the amount of threads present in the system. + /// @returns SizeT the amount of cores present. + SizeT Capacity() noexcept; + + private: + Array<HardwareThread, kMaxAPInsideSched> fThreadList; + ThreadID fCurrentThreadIdx{0}; +}; + +/// @brief wakes up thread. +/// wakes up thread from hang. +Void mp_wakeup_thread(HAL::StackFramePtr stack); + +/// @brief makes thread sleep. +/// hooks and hangs thread to prevent code from executing. +Void mp_hang_thread(HAL::StackFramePtr stack); +} // namespace Kernel + +#endif // !__INC_MP_MANAGER_H__ diff --git a/src/kernel/KernelKit/HeapMgr.h b/src/kernel/KernelKit/HeapMgr.h new file mode 100644 index 00000000..58bac7a5 --- /dev/null +++ b/src/kernel/KernelKit/HeapMgr.h @@ -0,0 +1,58 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef INC_KERNEL_HEAP_H +#define INC_KERNEL_HEAP_H + +/// @date 30/01/24 +/// @file: HeapMgr.h +/// @brief: Memory allocation support for the NeKernel. + +#include <KernelKit/KPC.h> +#include <NeKit/KernelPanic.h> +#include <hint/CompilerHint.h> + +namespace Kernel { +/// @brief Declare pointer as free. +/// @param heap_ptr the pointer. +/// @return a status code regarding the deallocation. +Int32 mm_free_ptr(VoidPtr heap_ptr); + +/// @brief Check if pointer is a valid Kernel pointer. +/// @param heap_ptr the pointer +/// @return if it exists it returns true. +Boolean mm_is_valid_ptr(VoidPtr heap_ptr); + +/// @brief Allocate chunk of memory. +/// @param sz Size of pointer +/// @param wr Read Write bit. +/// @param user User enable bit. +/// @return The newly allocated pointer, or nullptr. +VoidPtr mm_alloc_ptr(SizeT sz, Bool wr, Bool user, SizeT pad_amount = 0); + +/// @brief Protect the heap with a CRC value. +/// @param heap_ptr pointer. +/// @return if it valid: point has crc now., otherwise fail. +Boolean mm_protect_ptr(VoidPtr heap_ptr); + +/// @brief Makes a Kernel page. +/// @param heap_ptr the page pointer. +/// @return status code +Int32 mm_make_page(VoidPtr heap_ptr); + +/// @brief Overwrites and set the flags of a heap header. +/// @param heap_ptr the pointer to update. +/// @param flags the flags to set. +Int32 mm_set_ptr_flags(VoidPtr heap_ptr, UInt64 flags); + +/// @brief Gets the flags of a heap header. +/// @param heap_ptr the pointer to get. +UInt64 mm_get_ptr_flags(VoidPtr heap_ptr); +} // namespace Kernel + +#include <KernelKit/HeapMgr.inl> + +#endif // !INC_KERNEL_HEAP_H diff --git a/src/kernel/KernelKit/HeapMgr.inl b/src/kernel/KernelKit/HeapMgr.inl new file mode 100644 index 00000000..3231d33c --- /dev/null +++ b/src/kernel/KernelKit/HeapMgr.inl @@ -0,0 +1,35 @@ +/* ======================================== + + Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#ifndef INC_KERNEL_HEAP_H +#include <KernelKit/HeapMgr.h> +#endif // !INC_KERNEL_HEAP_H + +namespace Kernel { +/// @brief Allocate C++ class. +/// @param cls The class to allocate. +/// @param args The args to pass. +template <typename T, typename... Args> +inline BOOL mm_new_class(_Input _Output T** cls, _Input Args&&... args) { + if (*cls) { + err_global_get() = Kernel::kErrorInvalidData; + return NO; + } + + *cls = new T(move(args)...); + return *cls; +} + +/// @brief Delete and nullify C++ class. +/// @param cls The class to delete. +template <typename T> +inline Void mm_delete_class(_Input _Output T** cls) { + delete *cls; + *cls = nullptr; +} +} // namespace Kernel
\ No newline at end of file diff --git a/src/kernel/KernelKit/IDylibObject.h b/src/kernel/KernelKit/IDylibObject.h new file mode 100644 index 00000000..ef6b96db --- /dev/null +++ b/src/kernel/KernelKit/IDylibObject.h @@ -0,0 +1,45 @@ +/* + * ======================================================== + * + * Kernel + * Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + * + * ======================================================== + */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <NeKit/Defines.h> + +#define NE_DYLIB_OBJECT : public IDylibObject + +namespace Kernel { +class IDylibObject; + +/// @brief Dylib class object. A handle to a shared library. +class IDylibObject { + public: + explicit IDylibObject() = default; + virtual ~IDylibObject() = default; + + struct DylibTraits final { + VoidPtr ImageObject{nullptr}; + VoidPtr ImageEntrypointOffset{nullptr}; + + VoidPtr Image() const { return ImageObject; } + Bool IsValid() const { return ImageObject && ImageEntrypointOffset; } + }; + + NE_COPY_DEFAULT(IDylibObject) + + virtual DylibTraits** GetAddressOf() = 0; + virtual DylibTraits* Get() = 0; + + virtual Void Mount(DylibTraits* to_mount) = 0; + virtual Void Unmount() = 0; +}; + +/// @brief Pure implementation, missing method/function handler. +EXTERN_C void __ne_pure_call(void); +} // namespace Kernel diff --git a/src/kernel/KernelKit/IFS.h b/src/kernel/KernelKit/IFS.h new file mode 100644 index 00000000..7118a935 --- /dev/null +++ b/src/kernel/KernelKit/IFS.h @@ -0,0 +1,25 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <KernelKit/DriveMgr.h> + +namespace Kernel { +/// @brief Read from IFS disk. +/// @param Mnt mounted interface. +/// @param DrvTrait drive info +/// @param DrvIndex drive index. +/// @return +Int32 fs_ifs_read(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); + +/// @brief Write to IFS disk. +/// @param Mnt mounted interface. +/// @param DrvTrait drive info +/// @param DrvIndex drive index. +/// @return +Int32 fs_ifs_write(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); +} // namespace Kernel diff --git a/src/kernel/KernelKit/ILoader.h b/src/kernel/KernelKit/ILoader.h new file mode 100644 index 00000000..28dd1ed9 --- /dev/null +++ b/src/kernel/KernelKit/ILoader.h @@ -0,0 +1,32 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <NeKit/Defines.h> +#include <NeKit/ErrorOr.h> +#include <hint/CompilerHint.h> + +namespace Kernel { +/// @brief This interface is used to make loader contracts (MSCOFF, PEF). +/// @author @Amlal-El-Mahrouss +class ILoader { + public: + explicit ILoader() = default; + virtual ~ILoader() = default; + + NE_COPY_DEFAULT(ILoader) + + public: + virtual _Output ErrorOr<VoidPtr> GetBlob() = 0; + virtual _Output const Char* AsString() = 0; + virtual _Output const Char* MIME() = 0; + virtual _Output const Char* Path() = 0; + virtual _Output ErrorOr<VoidPtr> FindStart() = 0; + virtual _Output ErrorOr<VoidPtr> FindSymbol(_Input const Char* name, _Input Int32 kind) = 0; +}; +} // namespace Kernel diff --git a/src/kernel/KernelKit/IPEFDylibObject.h b/src/kernel/KernelKit/IPEFDylibObject.h new file mode 100644 index 00000000..17ef02d5 --- /dev/null +++ b/src/kernel/KernelKit/IPEFDylibObject.h @@ -0,0 +1,86 @@ +/* + * ======================================================== + * + * Kernel + * Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + * + * ======================================================== + */ + +#ifndef __KERNELKIT_PEF_SHARED_OBJECT_H__ +#define __KERNELKIT_PEF_SHARED_OBJECT_H__ + +#include <KernelKit/IDylibObject.h> +#include <KernelKit/PEF.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/ProcessScheduler.h> +#include <NeKit/Defines.h> + +namespace Kernel { +/** + * @brief Shared Library class + * Load library from this class + */ +class IPEFDylibObject final NE_DYLIB_OBJECT { + public: + explicit IPEFDylibObject() = default; + ~IPEFDylibObject() = default; + + public: + NE_COPY_DEFAULT(IPEFDylibObject) + + private: + DylibTraits* fMounted{nullptr}; + + public: + DylibTraits** GetAddressOf() { return &fMounted; } + + DylibTraits* Get() { return fMounted; } + + public: + void Mount(DylibTraits* to_mount) noexcept { + if (!to_mount || !to_mount->ImageObject) return; + + fMounted = to_mount; + + if (fLoader && to_mount) { + delete fLoader; + fLoader = nullptr; + } + + if (!fLoader) { + fLoader = new PEFLoader(fMounted->ImageObject); + } + } + + void Unmount() noexcept { + if (fMounted) fMounted = nullptr; + }; + + template <typename SymbolType> + SymbolType Load(const Char* symbol_name, const SizeT& len, const UInt32& kind) { + if (symbol_name == nullptr || *symbol_name == 0) return nullptr; + if (len > kPathLen || len < 1) return nullptr; + + auto ret = reinterpret_cast<SymbolType>(fLoader->FindSymbol(symbol_name, kind).Leak().Leak()); + + if (!ret) { + if (kind == kPefCode) return (VoidPtr) &__ne_pure_call; + + return nullptr; + } + + return ret; + } + + private: + PEFLoader* fLoader{nullptr}; +}; + +typedef IPEFDylibObject* IDylibRef; + +EXTERN_C IDylibRef rtl_init_dylib_pef(USER_PROCESS& header); +EXTERN_C Void rtl_fini_dylib_pef(USER_PROCESS& header, IDylibRef lib, Bool* successful); +} // namespace Kernel + +#endif /* ifndef __KERNELKIT_PEF_SHARED_OBJECT_H__ */ diff --git a/src/kernel/KernelKit/KPC.h b/src/kernel/KernelKit/KPC.h new file mode 100644 index 00000000..dbdc2a93 --- /dev/null +++ b/src/kernel/KernelKit/KPC.h @@ -0,0 +1,78 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <NeKit/Defines.h> + +/// @file KPC.h +/// @brief Kernel Procedure Code. + +#define err_local_ok() \ + (Kernel::UserProcessScheduler::The().TheCurrentProcess().Leak().GetLocalCode() == \ + Kernel::kErrorSuccess) +#define err_local_fail() \ + (Kernel::UserProcessScheduler::The().TheCurrentProcess().Leak().GetLocalCode() != \ + Kernel::kErrorSuccess) +#define err_local_get() \ + (Kernel::UserProcessScheduler::The().TheCurrentProcess().Leak().GetLocalCode()) + +#define err_global_ok() (Kernel::kErrorLocalNumber == Kernel::kErrorSuccess) +#define err_global_fail() (Kernel::kErrorLocalNumber != Kernel::kErrorSuccess) +#define err_global_get() (Kernel::kErrorLocalNumber) + +namespace Kernel { +typedef Int32 KPCError; + +inline KPCError kErrorLocalNumber = 0UL; + +inline constexpr KPCError kErrorSuccess = 0; +inline constexpr KPCError kErrorExecutable = 33; +inline constexpr KPCError kErrorExecutableLib = 34; +inline constexpr KPCError kErrorFileNotFound = 35; +inline constexpr KPCError kErrorDirectoryNotFound = 36; +inline constexpr KPCError kErrorDiskReadOnly = 37; +inline constexpr KPCError kErrorDiskIsFull = 38; +inline constexpr KPCError kErrorProcessFault = 39; +inline constexpr KPCError kErrorSocketHangUp = 40; +inline constexpr KPCError kErrorThreadLocalStorage = 41; +inline constexpr KPCError kErrorMath = 42; +inline constexpr KPCError kErrorNoNetwork = 43; +inline constexpr KPCError kErrorHeapOutOfMemory = 44; +inline constexpr KPCError kErrorNoSuchDisk = 45; +inline constexpr KPCError kErrorFileExists = 46; +inline constexpr KPCError kErrorFormatFailed = 47; +inline constexpr KPCError kErrorNetworkTimeout = 48; +inline constexpr KPCError kErrorInternal = 49; +inline constexpr KPCError kErrorForkAlreadyExists = 50; +inline constexpr KPCError kErrorOutOfTeamSlot = 51; +inline constexpr KPCError kErrorHeapNotPresent = 52; +inline constexpr KPCError kErrorNoEntrypoint = 53; +inline constexpr KPCError kErrorDiskIsCorrupted = 54; +inline constexpr KPCError kErrorDisk = 55; +inline constexpr KPCError kErrorInvalidData = 56; +inline constexpr KPCError kErrorAsync = 57; +inline constexpr KPCError kErrorNonBlocking = 58; +inline constexpr KPCError kErrorIPC = 59; +inline constexpr KPCError kErrorSign = 60; +inline constexpr KPCError kErrorInvalidCreds = 61; +inline constexpr KPCError kErrorCDTrayBroken = 62; +inline constexpr KPCError kErrorUnrecoverableDisk = 63; +inline constexpr KPCError kErrorFileLocked = 64; +inline constexpr KPCError kErrorDiskIsTooTiny = 65; +inline constexpr KPCError kErrorDmaExhausted = 66; +inline constexpr KPCError kErrorOutOfBitMapMemory = 67; +inline constexpr KPCError kErrorTimeout = 68; +inline constexpr KPCError kErrorAccessDenied = 69; +inline constexpr KPCError kErrorUnavailable = 70; +/// Generic errors. +inline constexpr KPCError kErrorUnimplemented = -1; + +/// @brief Does a system wide bug check. +/// @param void no params are needed. +/// @return if error-free: false, otherwise true. +Boolean err_bug_check_raise(Void) noexcept; +} // namespace Kernel diff --git a/src/kernel/KernelKit/KernelTaskScheduler.h b/src/kernel/KernelKit/KernelTaskScheduler.h new file mode 100644 index 00000000..9bfce1d6 --- /dev/null +++ b/src/kernel/KernelKit/KernelTaskScheduler.h @@ -0,0 +1,47 @@ +/* ======================================== + + Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +/// @file KernelTaskScheduler.h +/// @brief Kernel Task Scheduler header file. +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +#include <ArchKit/ArchKit.h> +#include <KernelKit/CoreProcessScheduler.h> +#include <KernelKit/LockDelegate.h> + +namespace Kernel { +class KernelTaskHelper; + +typedef ProcessID KID; + +/// @brief Equivalent of USER_PROCESS, but for kernel tasks. +/// @author Amlal +class KERNEL_TASK final { + public: + Char Name[kSchedNameLen] = {"KERNEL_TASK"}; + ProcessSubsystem SubSystem{ProcessSubsystem::kProcessSubsystemKernel}; + HAL::StackFramePtr StackFrame{nullptr}; + UInt8* StackReserve{nullptr}; + SizeT StackSize{kSchedMaxStackSz}; + ProcessImage Image{}; + /// @brief a KID is a Kernel ID, it is used to find a task running within + /// the kernel. + KID Kid{0}; +}; + +/// @brief Equivalent of UserProcessHelper, but for kernel tasks. +/// @author Amlal +class KernelTaskHelper final { + public: + STATIC Bool Add(HAL::StackFramePtr frame_ptr, ProcessID new_kid); + STATIC Bool Remove(const KID kid); + STATIC Bool CanBeScheduled(const KERNEL_TASK& process); + STATIC ErrorOr<KID> TheCurrentKID(); + STATIC SizeT StartScheduling(); +}; +} // namespace Kernel
\ No newline at end of file diff --git a/src/kernel/KernelKit/LockDelegate.h b/src/kernel/KernelKit/LockDelegate.h new file mode 100644 index 00000000..8ff67f19 --- /dev/null +++ b/src/kernel/KernelKit/LockDelegate.h @@ -0,0 +1,58 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <NeKit/Atom.h> +#include <NeKit/Defines.h> + +namespace Kernel { +enum { + kLockInvalid = 0, + kLockDone = 200, + kLockTimedOut = 300, + kLockCount = 3, +}; + +/// @brief Lock condition pointer. +typedef Boolean* LockPtr; + +/// @brief Locking delegate class, hangs until limit. +/// @tparam N the amount of cycles to wait. +template <SizeT N> +class LockDelegate final { + public: + LockDelegate() = delete; + + public: + explicit LockDelegate(LockPtr expr) { + auto spin = 0U; + + while (spin < N) { + if (*expr) { + fLockStatus | kLockDone; + break; + } + + ++spin; + } + + if (spin > N) fLockStatus | kLockTimedOut; + } + + ~LockDelegate() = default; + + LockDelegate& operator=(const LockDelegate&) = delete; + LockDelegate(const LockDelegate&) = delete; + + bool Done() { return fLockStatus[kLockDone] == kLockDone; } + + bool HasTimedOut() { return fLockStatus[kLockTimedOut] != kLockTimedOut; } + + private: + Atom<UInt> fLockStatus; +}; +} // namespace Kernel diff --git a/src/kernel/KernelKit/MSDOS.h b/src/kernel/KernelKit/MSDOS.h new file mode 100644 index 00000000..8c58b65b --- /dev/null +++ b/src/kernel/KernelKit/MSDOS.h @@ -0,0 +1,51 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: MSDOS.h + Purpose: MS-DOS header for Kernel. + + Revision History: + + 30/01/24: Added file (amlel) + +======================================== */ + +#ifndef __MSDOS_EXEC__ +#define __MSDOS_EXEC__ + +#include <KernelKit/PE.h> +#include <NeKit/Defines.h> + +// Last Rev +// Sat Feb 24 CET 2024 + +#define kMagMz0 'M' +#define kMagMz1 'Z' + +typedef Kernel::UInt32 DosWord; +typedef Kernel::Long DosLong; + +typedef struct _DosHeader { + Kernel::UInt8 eMagic[2]; + DosWord eMagLen; + DosWord ePagesCount; + DosWord eCrlc; + DosWord eCParHdr; + DosWord eMinAlloc; + DosWord eMaxAlloc; + DosWord eStackSeg; + DosWord eStackPtr; + DosWord eChksum; + DosWord eIp; + DosWord eCs; + DosWord eLfarlc; + DosWord eOvno; + DosWord eRes[4]; + DosWord eOemid; + DosWord eOeminfo; + DosWord eRes2[10]; + DosLong eLfanew; +} DosHeader, *DosHeaderPtr; + +#endif /* ifndef __MSDOS_EXEC__ */ diff --git a/src/kernel/KernelKit/PCI/DMA.h b/src/kernel/KernelKit/PCI/DMA.h new file mode 100644 index 00000000..80103dab --- /dev/null +++ b/src/kernel/KernelKit/PCI/DMA.h @@ -0,0 +1,75 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/PCI/Device.h> +#include <NeKit/Array.h> +#include <NeKit/OwnPtr.h> +#include <NeKit/Ref.h> + +namespace Kernel { +enum class DmaKind { + PCI = 10, // Bus mastering is required to be turned on. Basiaclly a request + // control system. 64-Bit access depends on the PAE bit and the device + // (if Double Address Cycle is available) + ISA, // Four DMA channels 0-3; 8 bit transfers and only a megabyte of RAM. + Count = 2, + Invalid = 0, +}; + +class DMAWrapper final { + public: + explicit DMAWrapper() = delete; + + public: + explicit DMAWrapper(nullPtr) = delete; + explicit DMAWrapper(voidPtr Ptr, DmaKind Kind = DmaKind::PCI) : fAddress(Ptr), fKind(Kind) {} + + public: + DMAWrapper& operator=(voidPtr Ptr); + + public: + DMAWrapper& operator=(const DMAWrapper&) = default; + DMAWrapper(const DMAWrapper&) = default; + + public: + ~DMAWrapper() = default; + + template <class T> + T* operator->(); + + template <class T> + T* Get(UIntPtr off = 0); + + public: + operator bool(); + bool operator!(); + + public: + bool Write(UIntPtr& bit, const UInt32& offset); + UIntPtr Read(const UInt32& offset); + Boolean Check(UIntPtr offset) const; + + public: + UIntPtr operator[](UIntPtr& offset); + + private: + voidPtr fAddress{nullptr}; + DmaKind fKind{DmaKind::Invalid}; + + private: + friend class DMAFactory; +}; + +class DMAFactory final { + public: + static OwnPtr<IOBuf<Char*>> Construct(OwnPtr<DMAWrapper>& dma); +}; +} // namespace Kernel + +#include <KernelKit/PCI/DMA.inl> diff --git a/src/kernel/KernelKit/PCI/DMA.inl b/src/kernel/KernelKit/PCI/DMA.inl new file mode 100644 index 00000000..d81a632e --- /dev/null +++ b/src/kernel/KernelKit/PCI/DMA.inl @@ -0,0 +1,17 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +namespace Kernel { +template <class T> +T* DMAWrapper::operator->() { + return this->fAddress; +} + +template <class T> +T* DMAWrapper::Get(UIntPtr offset) { + return reinterpret_cast<T*>((UIntPtr) this->fAddress + offset); +} +} // namespace Kernel diff --git a/src/kernel/KernelKit/PCI/Database.h b/src/kernel/KernelKit/PCI/Database.h new file mode 100644 index 00000000..463fde38 --- /dev/null +++ b/src/kernel/KernelKit/PCI/Database.h @@ -0,0 +1,51 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ +#pragma once + +#include <KernelKit/PCI/Device.h> +#include <NeKit/Defines.h> + +namespace Kernel { +namespace Types { + // https://wiki.osdev.org/PCI + enum class PciDeviceKind : UChar { + MassStorageController = 0x1, + NetworkController = 0x2, + DisplayController = 0x3, + MultimediaController = 0x4, + MemoryController = 0x5, + Bridge = 0x6, + CommunicationController = 0x7, + GenericSystemPeripheral = 0x8, + InputDeviceController = 0x9, + DockingStation = 0xa, + Processor = 0xb, + SerialBusController = 0xc, + WirelessController = 0xd, + IntelligentController = 0xe, + SatelliteCommunicationsController = 0xf, + CoProcessor = 0x40, + Unassgined = 0xf, + Invalid = Unassgined, + }; +} // namespace Types +} // namespace Kernel + +inline BOOL operator!=(const Kernel::Types::PciDeviceKind& lhs, Kernel::UChar rhs) { + return rhs != (Kernel::UChar) lhs; +} + +inline BOOL operator==(const Kernel::Types::PciDeviceKind& lhs, Kernel::UChar rhs) { + return rhs == (Kernel::UChar) lhs; +} + +inline BOOL operator!=(Kernel::UChar lhs, const Kernel::Types::PciDeviceKind& rhs) { + return lhs != (Kernel::UChar) rhs; +} + +inline BOOL operator==(Kernel::UChar lhs, const Kernel::Types::PciDeviceKind& rhs) { + return lhs == (Kernel::UChar) rhs; +}
\ No newline at end of file diff --git a/src/kernel/KernelKit/PCI/Device.h b/src/kernel/KernelKit/PCI/Device.h new file mode 100644 index 00000000..f2111e40 --- /dev/null +++ b/src/kernel/KernelKit/PCI/Device.h @@ -0,0 +1,73 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ +#pragma once + +#include <NeKit/Defines.h> + +namespace Kernel::PCI { +enum class PciConfigKind : UShort { + ConfigAddress = 0xCF8, + ConfigData = 0xCFC, + CommandReg = 0x0004, + Invalid = 0xFFFF, +}; + +/// @brief Device interface class +class Device final { + public: + Device() = default; + + public: + Device(UShort bus, UShort device, UShort function, UInt32 bar); + + Device& operator=(const Device&) = default; + Device(const Device&) = default; + + ~Device(); + + public: + UInt Read(UInt bar, Size szData); + void Write(UInt bar, UIntPtr data, Size szData); + + public: + operator bool(); + + public: + template <typename T> + UInt Read(UInt bar) { + static_assert(sizeof(T) <= sizeof(UInt32), "64-bit PCI addressing is unsupported"); + return Read(bar, sizeof(T)); + } + + template <typename T> + void Write(UInt bar, UIntPtr data) { + static_assert(sizeof(T) <= sizeof(UInt32), "64-bit PCI addressing is unsupported"); + Write(bar, data, sizeof(T)); + } + + public: + UShort DeviceId(); + UShort VendorId(); + UShort InterfaceId(); + UChar Class(); + UChar Subclass(); + UChar ProgIf(); + UChar HeaderType(); + UIntPtr Bar(UInt32 bar_in); + + public: + void EnableMmio(); + void BecomeBusMaster(); // for PCI-DMA, PC-DMA does not need that. + + UShort Vendor(); + + private: + UShort fBus; + UShort fDevice; + UShort fFunction; + UInt32 fBar; +}; +} // namespace Kernel::PCI diff --git a/src/kernel/KernelKit/PCI/Express.h b/src/kernel/KernelKit/PCI/Express.h new file mode 100644 index 00000000..484739ec --- /dev/null +++ b/src/kernel/KernelKit/PCI/Express.h @@ -0,0 +1,12 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <KernelKit/PCI/PCI.h> +#include <NeKit/Defines.h> + +#define PCI_EXPRESS_BUS_COUNT (4096) diff --git a/src/kernel/KernelKit/PCI/IO.h b/src/kernel/KernelKit/PCI/IO.h new file mode 100644 index 00000000..2ab72269 --- /dev/null +++ b/src/kernel/KernelKit/PCI/IO.h @@ -0,0 +1,63 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <ArchKit/ArchKit.h> +#include <NeKit/Array.h> +#include <NeKit/Defines.h> +#include <NeKit/Ref.h> + +namespace Kernel { +template <SizeT Sz> +class IOArray final { + public: + IOArray() = delete; + + IOArray(nullPtr) = delete; + + explicit IOArray(Array<UShort, Sz>& ports) : fPorts(ports) {} + + ~IOArray() {} + + IOArray& operator=(const IOArray&) = default; + + IOArray(const IOArray&) = default; + + operator bool() { return !fPorts.Empty(); } + + public: + template <typename T> + T In(SizeT index); + + template <typename T> + void Out(SizeT index, T value); + + private: + Array<UShort, Sz> fPorts; +}; + +inline constexpr UInt16 kMaxPorts = 16; + +using IOArray16 = IOArray<kMaxPorts>; + +template <SizeT Sz> +inline Array<UShort, Sz> make_ports(UShort base) { + Array<UShort, Sz> ports; + + for (UShort i = 0; i < Sz; ++i) { + ports[i] = base + i; + } + + return ports; +} +} // namespace Kernel + +#ifdef __NE_AMD64__ +#include <KernelKit/PCI/IOArray+AMD64.inl> +#else +#error Please provide platform specific code for the I/O +#endif // ifdef __NE_AMD64__ diff --git a/src/kernel/KernelKit/PCI/IOArray+AMD64.inl b/src/kernel/KernelKit/PCI/IOArray+AMD64.inl new file mode 100644 index 00000000..2b9125e0 --- /dev/null +++ b/src/kernel/KernelKit/PCI/IOArray+AMD64.inl @@ -0,0 +1,49 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: IO-Impl-AMD64.h + Purpose: I/O for AMD64. + + Revision History: + + 30/01/24: Add file. (amlel) + 02/02/24: Update I/O routines. (amlel) + +======================================== */ + +namespace Kernel { +template <SizeT Sz> +template <typename T> +T IOArray<Sz>::In(SizeT index) { + switch (sizeof(T)) { +#ifdef __NE_AMD64__ + case 4: + return HAL::rt_in32(fPorts[index].Leak()); + case 2: + return HAL::rt_in16(fPorts[index].Leak()); + case 1: + return HAL::rt_in8(fPorts[index].Leak()); +#endif + default: + return 0xFFFF; + } +} + +template <SizeT Sz> +template <typename T> +void IOArray<Sz>::Out(SizeT index, T value) { + switch (sizeof(T)) { +#ifdef __NE_AMD64__ + case 4: + HAL::rt_out32(fPorts[index].Leak(), value); + case 2: + HAL::rt_out16(fPorts[index].Leak(), value); + case 1: + HAL::rt_out8(fPorts[index].Leak(), value); +#endif + default: + break; + } +} +} // namespace Kernel
\ No newline at end of file diff --git a/src/kernel/KernelKit/PCI/Iterator.h b/src/kernel/KernelKit/PCI/Iterator.h new file mode 100644 index 00000000..5926049b --- /dev/null +++ b/src/kernel/KernelKit/PCI/Iterator.h @@ -0,0 +1,41 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef __PCI_ITERATOR_H__ +#define __PCI_ITERATOR_H__ + +#include <KernelKit/PCI/Database.h> +#include <KernelKit/PCI/Device.h> +#include <NeKit/Array.h> +#include <NeKit/Defines.h> +#include <NeKit/Ref.h> + +#define NE_BUS_COUNT (256) +#define NE_DEVICE_COUNT (33) +#define NE_FUNCTION_COUNT (8) + +namespace Kernel::PCI { +class Iterator final { + public: + Iterator() = delete; + + public: + explicit Iterator(const Types::PciDeviceKind deviceType, UInt32 bar); + + Iterator& operator=(const Iterator&) = default; + Iterator(const Iterator&) = default; + + ~Iterator(); + + public: + Ref<PCI::Device> operator[](const Size& sz); + + private: + Array<PCI::Device, NE_BUS_COUNT> fDevices; +}; +} // namespace Kernel::PCI + +#endif // __PCI_ITERATOR_H__ diff --git a/src/kernel/KernelKit/PCI/PCI.h b/src/kernel/KernelKit/PCI/PCI.h new file mode 100644 index 00000000..f76270da --- /dev/null +++ b/src/kernel/KernelKit/PCI/PCI.h @@ -0,0 +1,54 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <NeKit/Defines.h> + +#define kPCIConfigAddressPort (0xCF8) +#define kPCIConfigDataPort (0xCFC) + +#define kPCIDeviceCount (32) +#define kPCIFuncCount (8) +#define kPCIBusCount (256U) + +namespace Kernel::PCI { +// model +struct DeviceHeader { + UInt16 VendorId; + UInt16 DeviceId; + UInt8 Command; + UInt8 Status; + UInt8 RevisionId; + UInt8 ProgIf; + UInt8 SubClass; + UInt8 Class; + UInt8 CacheLineSz; + UInt8 LatencyTimer; + UInt8 HeaderType; + UInt8 Bist; + UInt8 Bus; + UInt8 Device; + UInt8 Function; +}; + +namespace Detail { + class BAR { + public: + UIntPtr BAR; + SizeT Size; + }; +} // namespace Detail + +class BAR { + public: + Detail::BAR BAR1; + Detail::BAR BAR2; + Detail::BAR BAR3; + Detail::BAR BAR4; + Detail::BAR BAR5; +}; +} // namespace Kernel::PCI diff --git a/src/kernel/KernelKit/PE.h b/src/kernel/KernelKit/PE.h new file mode 100644 index 00000000..b4b4576e --- /dev/null +++ b/src/kernel/KernelKit/PE.h @@ -0,0 +1,130 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: PE.h + Purpose: Portable Executable for Kernel. + + Revision History: + + 30/01/24: Added file (amlel) + +======================================== */ + +#ifndef __KERNELKIT_INC_PE_H__ +#define __KERNELKIT_INC_PE_H__ + +#include <NeKit/Defines.h> + +#define kPeSignature (0x00004550) + +#define kPeMagic32 (0x010b) +#define kPeMagic64 (0x020b) + +#define kPeMachineAMD64 (0x8664) +#define kPeMachineARM64 (0xaa64) + +typedef struct LDR_EXEC_HEADER final { + Kernel::UInt32 Signature; + Kernel::UInt16 Machine; + Kernel::UInt16 NumberOfSections; + Kernel::UInt32 TimeDateStamp; + Kernel::UInt32 PointerToSymbolTable; + Kernel::UInt32 NumberOfSymbols; + Kernel::UInt16 SizeOfOptionalHeader; + Kernel::UInt16 Characteristics; +} LDR_EXEC_HEADER, *LDR_EXEC_HEADER_PTR; + +typedef struct LDR_OPTIONAL_HEADER final { + Kernel::UInt16 Magic; // 0x010b - PE32, 0x020b - PE32+ (64 bit) + Kernel::UInt8 MajorLinkerVersion; + Kernel::UInt8 MinorLinkerVersion; + Kernel::UInt32 SizeOfCode; + Kernel::UInt32 SizeOfInitializedData; + Kernel::UInt32 SizeOfUninitializedData; + Kernel::UInt32 AddressOfEntryPoint; + Kernel::UInt32 BaseOfCode; + Kernel::UInt64 ImageBase; + Kernel::UInt32 SectionAlignment; + Kernel::UInt32 FileAlignment; + Kernel::UInt16 MajorOperatingSystemVersion; + Kernel::UInt16 MinorOperatingSystemVersion; + Kernel::UInt16 MajorImageVersion; + Kernel::UInt16 MinorImageVersion; + Kernel::UInt16 MajorSubsystemVersion; + Kernel::UInt16 MinorSubsystemVersion; + Kernel::UInt32 Win32VersionValue; + Kernel::UInt32 SizeOfImage; + Kernel::UInt32 SizeOfHeaders; + Kernel::UInt32 CheckSum; + Kernel::UInt16 Subsystem; + Kernel::UInt16 DllCharacteristics; + Kernel::UInt32 SizeOfStackReserve; + Kernel::UInt32 SizeOfStackCommit; + Kernel::UInt32 SizeOfHeapReserve; + Kernel::UInt32 SizeOfHeapCommit; + Kernel::UInt32 LoaderFlags; + Kernel::UInt32 NumberOfRvaAndSizes; +} LDR_OPTIONAL_HEADER, *LDR_OPTIONAL_HEADER_PTR; + +typedef struct LDR_SECTION_HEADER final { + Kernel::Char Name[8]; + Kernel::UInt32 VirtualSize; + Kernel::UInt32 VirtualAddress; + Kernel::UInt32 SizeOfRawData; + Kernel::UInt32 PointerToRawData; + Kernel::UInt32 PointerToRelocations; + Kernel::UInt32 PointerToLineNumbers; + Kernel::UInt16 NumberOfRelocations; + Kernel::UInt16 NumberOfLinenumbers; + Kernel::UInt32 Characteristics; +} LDR_SECTION_HEADER, *LDR_SECTION_HEADER_PTR; + +enum kExecDataDirParams { + kExecExport, + kExecImport, + kExecInvalid, + kExecCount, +}; + +typedef struct LDR_EXPORT_DIRECTORY { + Kernel::UInt32 Characteristics; + Kernel::UInt32 TimeDateStamp; + Kernel::UInt16 MajorVersion; + Kernel::UInt16 MinorVersion; + Kernel::UInt32 Name; + Kernel::UInt32 Base; + Kernel::UInt32 NumberOfFunctions; + Kernel::UInt32 NumberOfNames; + Kernel::UInt32 AddressOfFunctions; // export table rva + Kernel::UInt32 AddressOfNames; + Kernel::UInt32 AddressOfNameOrdinal; // ordinal table rva +} LDR_EXPORT_DIRECTORY, *LDR_EXPORT_DIRECTORY_PTR; + +typedef struct LDR_IMPORT_DIRECTORY { + union { + Kernel::UInt32 Characteristics; + Kernel::UInt32 OriginalFirstThunk; + }; + Kernel::UInt32 TimeDateStamp; + Kernel::UInt32 ForwarderChain; + Kernel::UInt32 NameRva; + Kernel::UInt32 ThunkTableRva; +} LDR_IMPORT_DIRECTORY, *LDR_IMPORT_DIRECTORY_PTR; + +typedef struct LDR_DATA_DIRECTORY { + Kernel::UInt32 VirtualAddress; + Kernel::UInt32 Size; +} LDR_DATA_DIRECTORY, *LDR_DATA_DIRECTORY_PTR; + +typedef struct LDR_IMAGE_HEADER { + LDR_EXEC_HEADER Header; + LDR_OPTIONAL_HEADER OptHdr; +} LDR_IMAGE_HEADER, *LDR_IMAGE_HEADER_PTR; + +enum { + kUserSection = 0x00000020, + kPEResourceId = 0xFFaadd00, +}; + +#endif /* ifndef __KERNELKIT_INC_PE_H__ */ diff --git a/src/kernel/KernelKit/PE32CodeMgr.h b/src/kernel/KernelKit/PE32CodeMgr.h new file mode 100644 index 00000000..52bc22b4 --- /dev/null +++ b/src/kernel/KernelKit/PE32CodeMgr.h @@ -0,0 +1,91 @@ +/* ======================================== + + Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: PE32CodeMgr.h + Purpose: PE32+ Code Mgr and Dylib mgr. + + Revision History: + + 12/02/24: Added file (amlel) + +======================================== */ + +#pragma once + +//////////////////////////////////////////////////// + +// LAST REV: Mon Feb 12 13:52:01 CET 2024 + +//////////////////////////////////////////////////// + +#include <KernelKit/FileMgr.h> +#include <KernelKit/ILoader.h> +#include <KernelKit/PE.h> +#include <NeKit/ErrorOr.h> +#include <NeKit/KString.h> + +#ifndef INC_PROCESS_SCHEDULER_H +#include <KernelKit/ProcessScheduler.h> +#endif + +#define kPeStackSizeSymbol "__NESizeOfReserveStack" +#define kPeHeapSizeSymbol "__NESizeOfReserveHeap" +#define kPeNameSymbol "__NEProgramName" + +#define kPeApplicationMime "application/vnd-portable-executable" + +#define kPeImageStart "__ImageStart" + +namespace Kernel { +/// +/// \name PE32Loader +/// \brief PE32+ loader class. +/// +class PE32Loader : public ILoader { + private: + explicit PE32Loader() = delete; + + public: + explicit PE32Loader(const VoidPtr blob); + explicit PE32Loader(const Char* path); + ~PE32Loader() override; + + public: + NE_COPY_DEFAULT(PE32Loader) + + public: + const Char* Path() override; + const Char* AsString() override; + const Char* MIME() override; + + public: + ErrorOr<VoidPtr> FindStart() override; + ErrorOr<VoidPtr> FindSectionByName(const Char* name); + ErrorOr<VoidPtr> FindSymbol(const Char* name, Int32 kind) override; + ErrorOr<VoidPtr> GetBlob() override; + + public: + bool IsLoaded() noexcept; + + private: +#ifdef __FSKIT_INCLUDES_NEFS__ + OwnPtr<FileStream<Char, NeFileSystemMgr>> fFile; +#elif defined(__FSKIT_INCLUDES_OPENHEFS__) + OwnPtr<FileStream<Char, HeFileSystemMgr>> fFile; +#else + OwnPtr<FileStream<Char>> fFile; +#endif // __FSKIT_INCLUDES_NEFS__ + + Ref<KString> fPath; + VoidPtr fCachedBlob; + BOOL fBad; +}; + +enum { kPEPlatformInvalid, kPEPlatformAMD64 = 100, kPEPlatformARM64 }; +enum { kPETypeInvalid, kPETypeText = 100, kPETypeData, kPETypeBSS }; + +typedef LDR_SECTION_HEADER PE_SECTION_INFO; + +ProcessID rtl_create_user_process(PE32Loader& exec, const Int32& process_kind) noexcept; +} // namespace Kernel
\ No newline at end of file diff --git a/src/kernel/KernelKit/PEF.h b/src/kernel/KernelKit/PEF.h new file mode 100644 index 00000000..94284c98 --- /dev/null +++ b/src/kernel/KernelKit/PEF.h @@ -0,0 +1,117 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: PEF.h + Purpose: Preferred Executable Format for Kernel. + + Revision History: + + ?/?/23: Added file (amlel) + +======================================== */ + +#ifndef __KERNELKIT_PEF_H__ +#define __KERNELKIT_PEF_H__ + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/ILoader.h> +#include <NeKit/Defines.h> + +#define kPefMagic "Open" +#define kPefMagicFat "nepO" + +#define kPefMagicLen (5) + +#define kPefVersion (0x0500) +#define kPefNameLen (256U) + +/* not mandatory, only for non fork based filesystems. */ +#define kPefExt ".exec" +#define kPefDylibExt ".dylib" +#define kPefLibExt ".lib" +#define kPefObjectExt ".obj" +#define kPefDebugExt ".dbg" +#define kPefDriverExt ".sys" + +// Kernel System Binary Interface. +#define kPefAbi (0x5046) + +#define kPefBaseOrigin (0x40000000) + +#define kPefStart "__ImageStart" +#define kPefMainSymbol "_NeMain" + +#define kPefForkKind kPefMagic +#define kPefForkKindFAT kPefMagicFat + +namespace Kernel { +enum { + kPefArchIntel86S, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64x0, /* 64x0. ISA */ + kPefArch32x0, /* 32x0. ISA */ + kPefArchPowerPC, + kPefArchARM64, + kPefArchCount = (kPefArchARM64 - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, +}; + +enum { + kPefSubArchGeneric = 0, + kPefSubArchAMD = 200, + kPefSubArchIntel, + kPefSubArchARM, + kPefSubArchIBM, +}; + +enum { + kPefKindInvalid = 0, + kPefKindExec = 1, /* .exec */ + kPefKindDylib = 2, /* .dylib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, +}; + +typedef struct PEFContainer final { + Char Magic[kPefMagicLen]; + UInt32 Linker; + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; + SizeT HdrSz; /* Size of header */ + SizeT Count; /* container header count */ + UInt32 Checksum; +} PACKED PEFContainer; + +/* First PEFCommandHeader starts after PEFContainer */ + +typedef struct PEFCommandHeader final { + Char Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* content offset */ + SizeT OffsetSize; /* offset size (physical size inside the file) */ + UIntPtr VMAddress; /* Virtual Address */ + SizeT VMSize; /* Virtual Size */ +} PACKED PEFCommandHeader; + +enum { + kPefInvalid = 0x0, + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + kPefCount = 4, +}; +} // namespace Kernel + +#endif /* ifndef __KERNELKIT_PEF_H__ */ diff --git a/src/kernel/KernelKit/PEFCodeMgr.h b/src/kernel/KernelKit/PEFCodeMgr.h new file mode 100644 index 00000000..41b135e0 --- /dev/null +++ b/src/kernel/KernelKit/PEFCodeMgr.h @@ -0,0 +1,75 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef _INC_CODE_MANAGER_PEF_H_ +#define _INC_CODE_MANAGER_PEF_H_ + +/// @file PEFCodeMgr.h +/// @brief PEF Code Manager header file. +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +#include <KernelKit/FileMgr.h> +#include <KernelKit/PEF.h> +#include <NeKit/ErrorOr.h> +#include <NeKit/KString.h> + +#ifndef INC_PROCESS_SCHEDULER_H +#include <KernelKit/ProcessScheduler.h> +#endif + +#define kPefApplicationMime "application/vnd-nekernel-executable" + +namespace Kernel { +/// +/// \name PEFLoader +/// \brief PEF loader class. +/// +class PEFLoader : public ILoader { + private: + explicit PEFLoader() = delete; + + public: + explicit PEFLoader(const VoidPtr blob); + explicit PEFLoader(const Char* path); + ~PEFLoader() override; + + public: + NE_COPY_DEFAULT(PEFLoader) + + public: + const Char* Path() override; + const Char* AsString() override; + const Char* MIME() override; + + public: + ErrorOr<VoidPtr> FindStart() override; + ErrorOr<VoidPtr> FindSymbol(const Char* name, Int32 kind) override; + ErrorOr<VoidPtr> GetBlob() override; + + public: + bool IsLoaded() noexcept; + + private: +#ifdef __FSKIT_INCLUDES_NEFS__ + OwnPtr<FileStream<Char, NeFileSystemMgr>> fFile; +#elif defined(__FSKIT_INCLUDES_OPENHEFS__) + OwnPtr<FileStream<Char, HeFileSystemMgr>> fFile; +#else + OwnPtr<FileStream<Char>> fFile; +#endif // __FSKIT_INCLUDES_NEFS__ + + Ref<KString> fPath; + VoidPtr fCachedBlob; + BOOL fFatBinary{}; + BOOL fBad{}; +}; + +namespace Utils { + ProcessID rtl_create_user_process(PEFLoader& exec, const Int32& procKind) noexcept; +} // namespace Utils +} // namespace Kernel + +#endif // ifndef _INC_CODE_MANAGER_PEF_H_ diff --git a/src/kernel/KernelKit/ProcessScheduler.h b/src/kernel/KernelKit/ProcessScheduler.h new file mode 100644 index 00000000..7414e4fe --- /dev/null +++ b/src/kernel/KernelKit/ProcessScheduler.h @@ -0,0 +1,18 @@ +/* ======================================== + + Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <KernelKit/KernelTaskScheduler.h> +#include <KernelKit/UserProcessScheduler.h> + +#ifdef __NEOSKRNL__ +namespace Kernel { +inline UserProcessTeam kLowUserTeam; +inline UserProcessTeam kHighUserTeam; +inline UserProcessTeam kMidUserTeam; +} // namespace Kernel +#endif
\ No newline at end of file diff --git a/src/kernel/KernelKit/Semaphore.h b/src/kernel/KernelKit/Semaphore.h new file mode 100644 index 00000000..831774a5 --- /dev/null +++ b/src/kernel/KernelKit/Semaphore.h @@ -0,0 +1,110 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +/// @author Amlal El Mahrouss +/// @file Semaphore.h +/// @brief Semaphore structure and functions for synchronization in the kernel. + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/Timer.h> +#include <NeKit/Defines.h> + +#define kSemaphoreOwnerIndex (0U) +#define kSemaphoreCountIndex (1U) + +#define kSemaphoreCount (2U) + +#define kSemaphoreIncrementOwner(sem) (sem[kSemaphoreOwnerIndex]++) +#define kSemaphoreDecrementOwner(sem) (sem[kSemaphoreOwnerIndex]--) + +namespace Kernel { +/// @brief Semaphore structure used for synchronization. +typedef UInt64 SemaphoreArr[kSemaphoreCount]; + +/// @brief Checks if the semaphore is valid. +inline BOOL rtl_sem_is_valid(const SemaphoreArr& sem, UInt64 owner = 0) { + return sem[kSemaphoreOwnerIndex] == owner && sem[kSemaphoreCountIndex] > 0; +} + +/// @brief Releases the semaphore, resetting its owner and count. +/// @param sem +/// @return +inline BOOL rtl_sem_release(SemaphoreArr& sem) { + sem[kSemaphoreOwnerIndex] = 0; + sem[kSemaphoreCountIndex] = 0; + + return TRUE; +} + +/// @brief Initializes the semaphore with an owner and a count of zero. +/// @param sem the semaphore array to use. +/// @param owner the owner to set, could be anything identifitable. +/// @return +inline BOOL rtl_sem_acquire(SemaphoreArr& sem, UInt64 owner) { + if (!owner) { + err_global_get() = kErrorInvalidData; + return FALSE; // Invalid owner + } + + sem[kSemaphoreOwnerIndex] = owner; + sem[kSemaphoreCountIndex] = 0; + + return TRUE; +} + +/// @brief Waits for the semaphore to be available, blocking until it is. +/// @param sem +/// @param timeout +/// @param condition condition pointer. +/// @return +inline BOOL rtl_sem_wait(SemaphoreArr& sem, UInt64 owner, UInt64 timeout, + BOOL* condition = nullptr) { + if (!rtl_sem_is_valid(sem, owner)) { + return FALSE; + } + + if (timeout <= 0) { + err_global_get() = kErrorTimeout; + + return FALSE; + } + + if (!condition || *condition) { + if (sem[kSemaphoreCountIndex] == 0) { + err_global_get() = kErrorUnavailable; + return FALSE; + } + + err_global_get() = kErrorSuccess; + sem[kSemaphoreCountIndex]--; + + return TRUE; + } + + HardwareTimer timer(timeout); + BOOL ret = timer.Wait(); + + if (ret) { + if (!condition || *condition) { + if (sem[kSemaphoreCountIndex] == 0) { + err_global_get() = kErrorUnavailable; + return FALSE; + } + + err_global_get() = kErrorSuccess; + sem[kSemaphoreCountIndex]--; + + return TRUE; + } + } + + err_global_get() = kErrorTimeout; + + return FALSE; // Failed to acquire semaphore +} +} // namespace Kernel
\ No newline at end of file diff --git a/src/kernel/KernelKit/ThreadLocalStorage.h b/src/kernel/KernelKit/ThreadLocalStorage.h new file mode 100644 index 00000000..205d6df9 --- /dev/null +++ b/src/kernel/KernelKit/ThreadLocalStorage.h @@ -0,0 +1,68 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef KERNELKIT_TLS_H +#define KERNELKIT_TLS_H + +#include <NeKit/Defines.h> +#include <NeKit/ErrorOr.h> + +///! @brief Thread Local Storage for NeKernel. + +#define kCookieMag0Idx (0U) +#define kCookieMag1Idx (1U) +#define kCookieMag2Idx (2U) + +#define kCookieMag0 'N' +#define kCookieMag1 'K' +#define kCookieMag2 'O' + +#define kCookieMagLen (3U) + +struct THREAD_INFORMATION_BLOCK; + +/// @brief Thread Information Block. +/// Located in GS on AMD64, other architectures have their own stuff. (64x0, 32x0, ARM64) +struct PACKED THREAD_INFORMATION_BLOCK final { + Kernel::Char Cookie[kCookieMagLen]{0}; //! Thread Magic Number. + Kernel::VoidPtr UserData{nullptr}; //! Thread Information Record (User defined canary structure) +}; + +///! @brief Cookie Sanity check. +Kernel::Boolean tls_check_tib(THREAD_INFORMATION_BLOCK* the_tib); + +///! @brief new ptr syscall. +template <typename T> +T* tls_new_ptr(void) noexcept; + +///! @brief delete ptr syscall. +template <typename T> +Kernel::Boolean tls_delete_ptr(T* ptr) noexcept; + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline Kernel::Bool tls_delete_ptr(Kernel::ErrorOr<T> obj) noexcept; + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline Kernel::Bool tls_delete_ptr(Kernel::ErrorOr<T*> obj) noexcept; + +template <typename T, typename... Args> +T* tls_new_class(Args&&... args); + +/// @brief TLS install TIB and PIB. (syscall) +EXTERN_C Kernel::Void rt_install_tib(THREAD_INFORMATION_BLOCK* TIB, THREAD_INFORMATION_BLOCK* PIB); + +/// @brief TLS check (syscall) +EXTERN_C Kernel::Bool tls_check_syscall_impl(Kernel::VoidPtr TIB) noexcept; + +#include <KernelKit/ThreadLocalStorage.inl> + +// last rev 7/7/24 + +#endif /* ifndef KERNELKIT_TLS_H */ diff --git a/src/kernel/KernelKit/ThreadLocalStorage.inl b/src/kernel/KernelKit/ThreadLocalStorage.inl new file mode 100644 index 00000000..66a3d282 --- /dev/null +++ b/src/kernel/KernelKit/ThreadLocalStorage.inl @@ -0,0 +1,89 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +//! @file ThreadLocalStorage.inl +//! @brief Allocate resources from the process's heap storage. + +#ifndef INC_PROCESS_SCHEDULER_H +#include <KernelKit/ProcessScheduler.h> +#endif + +template <typename T> +inline T* tls_new_ptr(void) noexcept { + using namespace Kernel; + + auto ref_process = UserProcessScheduler::The().TheCurrentProcess(); + MUST_PASS(ref_process); + + auto pointer = ref_process.Leak().New(sizeof(T)); + + if (pointer.Error()) return nullptr; + + return reinterpret_cast<T*>(pointer.Leak().Leak()); +} + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline Kernel::Bool tls_delete_ptr(T* obj) noexcept { + using namespace Kernel; + + if (!obj) return No; + + auto ref_process = UserProcessScheduler::The().TheCurrentProcess(); + MUST_PASS(ref_process); + + ErrorOr<T*> obj_wrapped{obj}; + + return ref_process.Leak().Delete(obj_wrapped); +} + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline Kernel::Bool tls_delete_ptr(Kernel::ErrorOr<T> obj) noexcept { + return tls_delete_ptr(obj.Leak()); +} + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline Kernel::Bool tls_delete_ptr(Kernel::ErrorOr<T*> obj) noexcept { + return tls_delete_ptr(obj->Leak()); +} + +/// @brief Allocate a C++ class, and then call the constructor of it. +/// @tparam T class type. +/// @tparam ...Args varg class type. +/// @param args arguments list. +/// @return Class instance. +template <typename T, typename... Args> +T* tls_new_class(Args&&... args) { + using namespace Kernel; + + T* obj = tls_new_ptr<T>(); + + if (obj) { + *obj = T(forward(args)...); + return obj; + } + + return nullptr; +} + +/// @brief Delete a C++ class (call constructor first.) +/// @tparam T +/// @param obj +/// @return +template <typename T> +inline Kernel::Bool tls_delete_class(T* obj) { + using namespace Kernel; + + if (!obj) return No; + + obj->~T(); + return tls_delete_ptr(obj); +} diff --git a/src/kernel/KernelKit/Timer.h b/src/kernel/KernelKit/Timer.h new file mode 100644 index 00000000..46db5671 --- /dev/null +++ b/src/kernel/KernelKit/Timer.h @@ -0,0 +1,75 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <ArchKit/ArchKit.h> +#include <KernelKit/KPC.h> + +namespace Kernel { +class SoftwareTimer; +class TimerInterface; + +inline constexpr Int16 kTimeUnit = 1000; + +class TimerInterface { + public: + /// @brief Default constructor + explicit TimerInterface() = default; + virtual ~TimerInterface() = default; + + public: + NE_COPY_DEFAULT(TimerInterface) + + public: + virtual BOOL Wait() noexcept; +}; + +class SoftwareTimer final : public TimerInterface { + public: + explicit SoftwareTimer(Int64 seconds); + ~SoftwareTimer() override; + + public: + NE_COPY_DEFAULT(SoftwareTimer) + + public: + BOOL Wait() noexcept override; + + private: + UIntPtr* fDigitalTimer{nullptr}; + Int64 fWaitFor{0}; +}; + +class HardwareTimer final : public TimerInterface { + public: + explicit HardwareTimer(UInt64 seconds); + ~HardwareTimer() override; + + public: + NE_COPY_DEFAULT(HardwareTimer) + + public: + BOOL Wait() noexcept override; + + private: + volatile UInt8* fDigitalTimer{nullptr}; + Int64 fWaitFor{0}; +}; + +inline UInt64 rtl_microseconds(UInt64 time) { + if (time < 1) return 0; + + // TODO: nanoseconds maybe? + return time / kTimeUnit; +} + +inline UInt64 rtl_milliseconds(UInt64 time) { + if (time < 1) return 0; + + return time; +} +} // namespace Kernel diff --git a/src/kernel/KernelKit/TraceSrv.h b/src/kernel/KernelKit/TraceSrv.h new file mode 100644 index 00000000..df188ea2 --- /dev/null +++ b/src/kernel/KernelKit/TraceSrv.h @@ -0,0 +1,22 @@ +/* ======================================== + + Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + NeKernel is licensed under the Apache License 2.0 license. + +======================================== */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> + +namespace Kernel { +namespace Detail { + inline constexpr auto kDebugCmdLen = 256U; + inline constexpr auto kDebugPort = 51820; + inline constexpr auto kDebugMagic = "NE1.0.0;"; + inline constexpr auto kDebugVersion = 0x0100; + inline constexpr auto kDebugDelim = ';'; + inline constexpr auto kDebugEnd = '\r'; + typedef UInt64 dk_socket_type; +} // namespace Detail +} // namespace Kernel
\ No newline at end of file diff --git a/src/kernel/KernelKit/UserMgr.h b/src/kernel/KernelKit/UserMgr.h new file mode 100644 index 00000000..3ce6254d --- /dev/null +++ b/src/kernel/KernelKit/UserMgr.h @@ -0,0 +1,95 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef INC_USER_H +#define INC_USER_H + +/* ======================================== + + Revision History: + + 04/03/25: Set users directory as /libSystem/ instead of /usr/ + + ======================================== */ + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/KPC.h> +#include <NeKit/Defines.h> +#include <NeKit/KString.h> + +///! We got the MGMT, STD (%s format) and GUEST users, +///! all are used to make authorized operations. +#define kMgmtUser "NEKERNEL/MGMT/%s" +#define kGuestUser "NEKERNEL/GUEST/%s" +#define kStdUser "NEKERNEL/STD/%s" + +#define kUsersDir "/users/" + +#define kMaxUserNameLen (256U) +#define kMaxUserTokenLen (256U) + +namespace Kernel { +class User; + +enum class UserRingKind : Int32 { + kRingInvalid = 0, + kRingStdUser = 444, + kRingSuperUser = 666, + kRingGuestUser = 777, + kRingCount = 3, +}; + +typedef Char* UserPublicKey; +typedef Char UserPublicKeyType; + +/// @brief System User class. +class User final { + public: + User() = delete; + + User(const Int32& sel, const Char* username); + User(const UserRingKind& kind, const Char* username); + + ~User(); + + public: + NE_COPY_DEFAULT(User) + + public: + bool operator==(const User& lhs); + bool operator!=(const User& lhs); + + public: + /// @brief Get software ring + const UserRingKind& Ring() noexcept; + + /// @brief Get user name + Char* Name() noexcept; + + /// @brief Is he a standard user? + Bool IsStdUser() noexcept; + + /// @brief Is she a super user? + Bool IsSuperUser() noexcept; + + /// @brief Saves a password from the public key. + Bool Save(const UserPublicKey password) noexcept; + + /// @brief Checks if a password matches the **password**. + /// @param password the password to check. + Bool Login(const UserPublicKey password) noexcept; + + private: + UserRingKind mUserRing{UserRingKind::kRingStdUser}; + Char mUserName[kMaxUserNameLen] = {0}; + UInt64 mUserFNV{0UL}; +}; + +inline User* kCurrentUser = nullptr; +inline User* kRootUser = nullptr; +} // namespace Kernel + +#endif /* ifndef INC_USER_H */ diff --git a/src/kernel/KernelKit/UserProcessScheduler.h b/src/kernel/KernelKit/UserProcessScheduler.h new file mode 100644 index 00000000..b2ab7dc2 --- /dev/null +++ b/src/kernel/KernelKit/UserProcessScheduler.h @@ -0,0 +1,243 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef INC_PROCESS_SCHEDULER_H +#define INC_PROCESS_SCHEDULER_H + +/// @file UserProcessScheduler.h +/// @brief User Process Scheduler header file. +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +#include <ArchKit/ArchKit.h> +#include <KernelKit/CoreProcessScheduler.h> +#include <KernelKit/LockDelegate.h> +#include <KernelKit/UserMgr.h> +#include <NeKit/MutableArray.h> + +//////////////////////////////////////////////////// +// Last revision date is: Fri Mar 28 2025 // +//////////////////////////////////////////////////// + +namespace Kernel { +//! @brief Forward declarations. + +class IDylibObject; +class UserProcessScheduler; +class UserProcessHelper; + +/***********************************************************************************/ +/// @name USER_PROCESS +/// @brief USER_PROCESS class, holds information about the running process/thread. +/***********************************************************************************/ +class USER_PROCESS final { + public: + explicit USER_PROCESS(); + ~USER_PROCESS(); + + public: + NE_COPY_DEFAULT(USER_PROCESS) + + public: + Char Name[kSchedNameLen] = {"USER_PROCESS"}; + ProcessSubsystem SubSystem{ProcessSubsystem::kProcessSubsystemUser}; + User* Owner{nullptr}; + HAL::StackFramePtr StackFrame{nullptr}; + AffinityKind Affinity{AffinityKind::kStandard}; + ProcessStatusKind Status{ProcessStatusKind::kKilled}; + UInt8 StackReserve[kSchedMaxStackSz]; + ProcessImage Image{}; + SizeT StackSize{kSchedMaxStackSz}; + IDylibObject* DylibDelegate{nullptr}; + SizeT MemoryCursor{0UL}; + SizeT MemoryLimit{kSchedMaxMemoryLimit}; + SizeT UsedMemory{0UL}; + + struct USER_PROCESS_SIGNAL final { + UIntPtr SignalArg{0}; + ProcessStatusKind Status{ProcessStatusKind::kKilled}; + UIntPtr SignalID{0}; + }; + + USER_PROCESS_SIGNAL Signal; + PROCESS_FILE_TREE<VoidPtr>* FileTree{nullptr}; + PROCESS_HEAP_TREE<VoidPtr>* HeapTree{nullptr}; + UserProcessTeam* ParentTeam; + + VoidPtr VMRegister{0UL}; + + enum { + kInvalidExecutableKind, + kExecutableKind, + kExecutableDylibKind, + kExecutableKindCount, + }; + + ProcessTime PTime{0}; //! @brief Process allocated tine. + ProcessTime RTime{0}; //! @brief Process run time. + ProcessTime UTime{0}; //! #brief Process used time. + + ProcessID ProcessId{kSchedInvalidPID}; + Int32 Kind{kExecutableKind}; + + public: + /***********************************************************************************/ + //! @brief boolean operator, check status. + /***********************************************************************************/ + explicit operator bool(); + + /***********************************************************************************/ + ///! @brief Crashes the app, exits with code ~0. + /***********************************************************************************/ + Void Crash(); + + /***********************************************************************************/ + ///! @brief Spawns a dynamic library handle if dylib. + /***********************************************************************************/ + Bool InitDylib(); + + /***********************************************************************************/ + ///! @brief Exits the app. + /***********************************************************************************/ + Void Exit(const Int32& exit_code = 0); + + /***********************************************************************************/ + ///! @brief TLS allocate. + ///! @param sz size of data structure. + ///! @param pad_amount amount to add after pointer. + ///! @return A wrapped pointer, or error code. + /***********************************************************************************/ + ErrorOr<VoidPtr> New(SizeT sz, SizeT pad_amount = 0); + + /***********************************************************************************/ + ///! @brief TLS free. + ///! @param ptr the pointer to free. + ///! @param sz the size of it. + /***********************************************************************************/ + template <typename T> + Boolean Delete(ErrorOr<T*> ptr); + + /***********************************************************************************/ + ///! @brief Wakes up thread. + /***********************************************************************************/ + Void Wake(Bool wakeup = false); + + public: + /***********************************************************************************/ + //! @brief Gets the local exit code. + /***********************************************************************************/ + KPCError& GetExitCode() noexcept; + + /***********************************************************************************/ + ///! @brief Get the process's name + ///! @example 'C Runtime Library' + /***********************************************************************************/ + const Char* GetName() noexcept; + + /***********************************************************************************/ + //! @brief return local error code of process. + //! @return Int32 local error code. + /***********************************************************************************/ + KPCError& GetLocalCode() noexcept; + + const User* GetOwner() noexcept; + const ProcessStatusKind& GetStatus() noexcept; + const AffinityKind& GetAffinity() noexcept; + + private: + KPCError LastExitCode{0}; + KPCError LocalCode{0}; + + friend UserProcessScheduler; + friend UserProcessHelper; +}; + +typedef Array<USER_PROCESS, kSchedProcessLimitPerTeam> USER_PROCESS_ARRAY; +typedef Ref<USER_PROCESS> USER_PROCESS_REF; + +/// \brief Processs Team (contains multiple processes inside it.) +/// Equivalent to a process batch +class UserProcessTeam final { + public: + explicit UserProcessTeam(); + ~UserProcessTeam() = default; + + NE_COPY_DEFAULT(UserProcessTeam) + + Array<USER_PROCESS, kSchedProcessLimitPerTeam>& AsArray(); + Ref<USER_PROCESS>& AsRef(); + ProcessID& Id() noexcept; + + public: + USER_PROCESS_ARRAY mProcessList; + USER_PROCESS_REF mCurrentProcess; + ProcessID mTeamId{0}; + ProcessID mProcessCur{0}; +}; + +/***********************************************************************************/ +/// @brief USER_PROCESS scheduler class. +/// The main class which you call to schedule user processes. +/***********************************************************************************/ +class UserProcessScheduler final : public ISchedulable { + friend class UserProcessHelper; + + public: + explicit UserProcessScheduler() = default; + ~UserProcessScheduler() override = default; + + NE_COPY_DELETE(UserProcessScheduler) + NE_MOVE_DELETE(UserProcessScheduler) + + public: + explicit operator bool(); + bool operator!(); + + public: + UserProcessTeam& TheCurrentTeam(); + BOOL SwitchTeam(UserProcessTeam& team); + + public: + ProcessID Spawn(const Char* name, VoidPtr code, VoidPtr image); + Void Remove(ProcessID process_id); + + Bool IsUser() override; + Bool IsKernel() override; + Bool HasMP() override; + + public: + USER_PROCESS_REF& TheCurrentProcess(); + SizeT Run() noexcept; + + public: + STATIC UserProcessScheduler& The(); + + private: + UserProcessTeam mTeam{}; +}; + +/***********************************************************************************/ +/** + * \brief USER_PROCESS helper class, which contains needed utilities for the scheduler. + */ +/***********************************************************************************/ + +class UserProcessHelper final { + public: + STATIC Bool Switch(HAL::StackFramePtr frame_ptr, ProcessID new_pid); + STATIC Bool CanBeScheduled(const USER_PROCESS& process); + STATIC ErrorOr<ProcessID> TheCurrentPID(); + STATIC SizeT StartScheduling(); +}; +} // namespace Kernel + +#include <KernelKit/ThreadLocalStorage.h> +#include <KernelKit/UserProcessScheduler.inl> + +//////////////////////////////////////////////////// +// END +//////////////////////////////////////////////////// + +#endif /* ifndef INC_PROCESS_SCHEDULER_H */ diff --git a/src/kernel/KernelKit/UserProcessScheduler.inl b/src/kernel/KernelKit/UserProcessScheduler.inl new file mode 100644 index 00000000..3d3659d6 --- /dev/null +++ b/src/kernel/KernelKit/UserProcessScheduler.inl @@ -0,0 +1,64 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + FILE: UserProcessScheduler.inl + PURPOSE: Low level/Ring-3 process scheduler. + +======================================== */ + +/// @brief USER_PROCESS inline definitions. +/// @author Amlal El Mahrouss (amlal@nekernel.org) +/// @date Tue Apr 22 22:01:07 CEST 2025 + +#ifndef INC_PROCESS_SCHEDULER_H +#include <KernelKit/UserProcessScheduler.h> +#endif // INC_PROCESS_SCHEDULER_H + +namespace Kernel { +/***********************************************************************************/ +/** @brief Free pointer/file from usage. */ +/***********************************************************************************/ + +template <typename T> +BOOL USER_PROCESS::Delete(ErrorOr<T*> ptr) { + if (!ptr) return No; + + if (!this->HeapTree) { + kout << "USER_PROCESS's heap is empty.\r"; + return No; + } + + PROCESS_HEAP_TREE<VoidPtr>* entry = this->HeapTree; + + while (entry != nullptr) { + if (entry->Entry == ptr.Leak().Leak()) { + this->UsedMemory -= entry->EntrySize; + +#ifdef __NE_AMD64__ + auto pd = hal_read_cr3(); + + hal_write_cr3(this->VMRegister); + + auto ret = mm_free_ptr(entry->Entry); + + hal_write_cr3(pd); + + return ret == kErrorSuccess; +#else + Bool ret = mm_free_ptr(ptr.Leak().Leak()); + + return ret == kErrorSuccess; +#endif + } + + entry = entry->Next; + } + + kout << "USER_PROCESS: Trying to free a pointer which doesn't exist.\r"; + + this->Crash(); + + return No; +} +} // namespace Kernel diff --git a/src/kernel/KernelKit/XCOFF.h b/src/kernel/KernelKit/XCOFF.h new file mode 100644 index 00000000..cbee6100 --- /dev/null +++ b/src/kernel/KernelKit/XCOFF.h @@ -0,0 +1,51 @@ +/* ======================================== + + Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + + File: XCOFF.h + Purpose: XCOFF for Kernel. + + Revision History: + + 04/07/24: Added file (amlel) + +======================================== */ + +#ifndef INC_XOCFF_H +#define INC_XOCFF_H + +#include <NeKit/Defines.h> + +#define kXCOFF64Magic (0x01F7) +#define kXCOFF64ForkNameLen (256U) + +#define kXCOFFRelFlg (0x0001) +#define kXCOFFExecutable (0x0002) +#define kXCOFFLnno (0x0004) +#define kXCOFFLSyms (0x0008) + +struct XCOFF_FILE_HEADER; +struct XCOFF_FORK_HEADER; + +/// @brief XCoff file header, meant for POWER apps. +typedef struct XCOFF_FILE_HEADER { + Kernel::UInt16 fMagic; + Kernel::UInt16 fTarget; + Kernel::UInt16 fNumSecs; + Kernel::UInt32 fTimeDat; + Kernel::UIntPtr fSymPtr; + Kernel::UInt32 fNumSyms; + Kernel::UInt16 fOptHdr; // ?: Number of bytes in optional header +} XCOFF_FILE_HEADER, XCOFF_FILE_HEADER32, XCOFF_FILE_HEADER64; + +/// @brief This the executable's manifest fork, designed for NeFS. +/// @param fPropertiesXMLFork The XML fork of the executable. +/// @param fDynamicLoaderFork The DYLD fork metadata. +/// @param fCodeSignFork Executable's certificate contained in a fork. +typedef struct XCOFF_FORK_HEADER { + Kernel::Char fPropertiesXMLFork[kXCOFF64ForkNameLen]; + Kernel::Char fDynamicLoaderFork[kXCOFF64ForkNameLen]; + Kernel::Char fCodeSignFork[kXCOFF64ForkNameLen]; +} XCOFF_FORK_HEADER; + +#endif // ifndef INC_XOCFF_H diff --git a/src/kernel/KernelKit/ZXD.h b/src/kernel/KernelKit/ZXD.h new file mode 100644 index 00000000..a4b07bfa --- /dev/null +++ b/src/kernel/KernelKit/ZXD.h @@ -0,0 +1,53 @@ +/* ======================================== + + Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <NeKit/Defines.h> + +#define kZXDMagicNumber (0x2010AF) +#define kZXDVersion (0x0001) + +namespace Kernel { +struct ZXD_EXEC_HEADER; +struct ZXD_STUB_HEADER; + +enum ZXD_FLAGS { + kZXDFlagsInvalid, + kZXDFlagsDriver, + kZXDFlagsCount, +}; + +/// @brief ZXD executable header +/// @details This header is used to identify ZXD executable files. +struct PACKED ZXD_EXEC_HEADER final { + UInt32 fMagic; + UInt32 fVersion; + UInt32 fFlags; + UInt32 fHdrSize; + UInt32 fCRC32; + UInt32 fAssigneeSignature; + UInt32 fIssuerSingature; + UIntPtr fExecOffset; + SizeT fExecSize; + UIntPtr fStubOffset; + SizeT fStubSize; + SizeT fStubAlign; + SizeT fStubCount; +}; + +/// @brief ZXD stub header +/// @details This header is used to identify ZXD stub files. It contains the size of the stub, the +/// offset of the stub, and the CRC32 checksum of the stub. +struct PACKED ZXD_STUB_HEADER final { + UInt32 fStubSize; + UInt32 fStubOffset; + UInt32 fStubCRC32; +}; + +using ZXD_EXEC_HEADER_PTR = ZXD_EXEC_HEADER*; +using ZXD_STUB_HEADER_PTR = ZXD_STUB_HEADER*; +} // namespace Kernel |
