diff options
Diffstat (limited to 'dev/kernel/src')
58 files changed, 5935 insertions, 0 deletions
diff --git a/dev/kernel/src/ACPIFactoryInterface.cc b/dev/kernel/src/ACPIFactoryInterface.cc new file mode 100644 index 00000000..3cc76e44 --- /dev/null +++ b/dev/kernel/src/ACPIFactoryInterface.cc @@ -0,0 +1,101 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <NewKit/KString.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/MemoryMgr.h> + +namespace NeOS +{ + /// @brief Finds a descriptor table inside ACPI XSDT. + ErrorOr<voidPtr> ACPIFactoryInterface::Find(const Char* signature) + { + MUST_PASS(this->fRsdp); + + if (!signature) + return ErrorOr<voidPtr>{-1}; + + if (*signature == 0) + return ErrorOr<voidPtr>{-1}; + + RSDP* rsp_ptr = reinterpret_cast<RSDP*>(this->fRsdp); + + if (rsp_ptr->Revision <= 1) + return ErrorOr<voidPtr>{-1}; + + RSDT* xsdt = reinterpret_cast<RSDT*>(rsp_ptr->RsdtAddress); + + Int64 num = (xsdt->Length - sizeof(SDT)) / sizeof(Int64); + + /*** + crucial to avoid underflows. + */ + if (num < 1) + { + /// stop here, we should have entries... + ke_panic(RUNTIME_CHECK_ACPI); + return ErrorOr<voidPtr>{-1}; + } + + this->fEntries = num; + + kout << "ACPI: Number of entries: " << number(this->fEntries) << kendl; + kout << "ACPI: Revision: " << number(xsdt->Revision) << kendl; + kout << "ACPI: Signature: " << xsdt->Signature << kendl; + kout << "ACPI: Address of XSDT: " << hex_number((UIntPtr)xsdt) << kendl; + + const short cAcpiSignatureLength = 4; + + for (Size index = 0; index < this->fEntries; ++index) + { + SDT* sdt = reinterpret_cast<SDT*>(xsdt->AddressArr[index]); + + kout << "ACPI: Checksum: " << number(sdt->Checksum) << kendl; + kout << "ACPI: Revision: " << number(sdt->Revision) << kendl; + + for (short signature_index = 0; signature_index < cAcpiSignatureLength; ++signature_index) + { + if (sdt->Signature[signature_index] != signature[signature_index]) + break; + + if (signature_index == (cAcpiSignatureLength - 1)) + { + kout << "ACPI: SDT Signature: " << sdt->Signature << kendl; + kout << "ACPI: SDT OEM ID: " << sdt->OemId << kendl; + return ErrorOr<voidPtr>(reinterpret_cast<voidPtr>(xsdt->AddressArr[index])); + } + } + } + + return ErrorOr<voidPtr>{-1}; + } + + /*** + @brief Checksum on SDT header. + @param checksum the header to checksum + @param len the length of it. + */ + bool ACPIFactoryInterface::Checksum(const Char* checksum, SSizeT len) + { + if (len == 0) + return 1; + + char chr = 0; + + for (int index = 0; index < len; ++index) + { + chr += checksum[index]; + } + + return chr == 0; + } + + ErrorOr<voidPtr> ACPIFactoryInterface::operator[](const Char* signature) + { + return this->Find(signature); + } +} // namespace NeOS diff --git a/dev/kernel/src/Array.cc b/dev/kernel/src/Array.cc new file mode 100644 index 00000000..29baf162 --- /dev/null +++ b/dev/kernel/src/Array.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Array.h> diff --git a/dev/kernel/src/ArrayList.cc b/dev/kernel/src/ArrayList.cc new file mode 100644 index 00000000..f7221b19 --- /dev/null +++ b/dev/kernel/src/ArrayList.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/ArrayList.h> diff --git a/dev/kernel/src/Atom.cc b/dev/kernel/src/Atom.cc new file mode 100644 index 00000000..92620c27 --- /dev/null +++ b/dev/kernel/src/Atom.cc @@ -0,0 +1,10 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Atom.h> + +// @file Atom.cpp +// @brief Atomic primitives diff --git a/dev/kernel/src/BinaryMutex.cc b/dev/kernel/src/BinaryMutex.cc new file mode 100644 index 00000000..4fdaa8f4 --- /dev/null +++ b/dev/kernel/src/BinaryMutex.cc @@ -0,0 +1,74 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/BinaryMutex.h> + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Unlocks the semaphore. + /***********************************************************************************/ + Bool BinaryMutex::Unlock() noexcept + { + if (fLockingProcess) + { + fLockingProcess = UserProcess(); + fLockingProcess.Status = ProcessStatusKind::kFrozen; + return Yes; + } + + return No; + } + + /***********************************************************************************/ + /// @brief Locks process in the semaphore. + /***********************************************************************************/ + Bool BinaryMutex::Lock(UserProcess& process) + { + if (!process || fLockingProcess) + return No; + + fLockingProcess = process; + + return Yes; + } + + /***********************************************************************************/ + /// @brief Checks if process is locked. + /***********************************************************************************/ + Bool BinaryMutex::IsLocked() const + { + return fLockingProcess.Status == ProcessStatusKind::kRunning; + } + + /***********************************************************************************/ + /// @brief Try lock or wait. + /***********************************************************************************/ + Bool BinaryMutex::LockOrWait(UserProcess& process, TimerInterface* timer) + { + if (timer == nullptr) + return No; + + this->Lock(process); + + timer->Wait(); + + return this->Lock(process); + } + + /***********************************************************************************/ + /// @brief Wait for process **sec** until we check if it's free. + /// @param sec seconds. + /***********************************************************************************/ + BOOL BinaryMutex::WaitForProcess(const Int16& sec) noexcept + { + HardwareTimer hw_timer(rtl_seconds(sec)); + hw_timer.Wait(); + + return !this->IsLocked(); + } +} // namespace NeOS diff --git a/dev/kernel/src/BitMapMgr.cc b/dev/kernel/src/BitMapMgr.cc new file mode 100644 index 00000000..18b1a156 --- /dev/null +++ b/dev/kernel/src/BitMapMgr.cc @@ -0,0 +1,195 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> + +#ifdef __NE_AMD64__ +#include <HALKit/AMD64/Paging.h> +#elif defined(__NE_ARM64__) +#include <HALKit/ARM64/Paging.h> +#endif + +#include <NewKit/Defines.h> +#include <NewKit/KernelPanic.h> + +#define kBitMapMagic (0x10210U) +#define kBitMapPadSize (mib_cast(16)) + +#define kBitMapMagIdx (0U) +#define kBitMapSizeIdx (1U) +#define kBitMapUsedIdx (2U) + +namespace NeOS +{ + namespace HAL + { + namespace Detail + { + /// \brief Proxy Interface to allocate a bitmap. + class IBitMapProxy final + { + public: + explicit IBitMapProxy() = default; + ~IBitMapProxy() = default; + + NE_COPY_DELETE(IBitMapProxy); + + auto IsBitMap(VoidPtr page_ptr) -> Bool + { + if (!page_ptr) + return No; + + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(page_ptr); + + if (!ptr_bit_set[kBitMapMagIdx] || + ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) + return No; + + return Yes; + } + + auto FreeBitMap(VoidPtr page_ptr) -> Bool + { + if (this->IsBitMap(page_ptr) == No) + return No; + + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(page_ptr); + + ptr_bit_set[kBitMapMagIdx] = kBitMapMagic; + ptr_bit_set[kBitMapUsedIdx] = No; + + this->GetBitMapStatus(ptr_bit_set); + + return Yes; + } + + UInt32 MakeMMFlags(Bool wr, Bool user) + { + UInt32 flags = kMMFlagsPresent; + + if (wr) + flags |= kMMFlagsWr; + + if (user) + flags |= kMMFlagsUser; + + return flags; + } + + /// @brief Iterate over availables pages for a free one. + /// @return The new address which was found. + auto FindBitMap(VoidPtr base_ptr, SizeT size, Bool wr, Bool user) -> VoidPtr + { + if (!size) + return nullptr; + + VoidPtr base = reinterpret_cast<VoidPtr>(((UIntPtr)base_ptr) + kPageSize); + + static SizeT biggest_block = 0UL; + + while (YES) + { + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(base); + + if (ptr_bit_set[kBitMapMagIdx] == kBitMapMagic && + ptr_bit_set[kBitMapSizeIdx] == size) + { + if (ptr_bit_set[kBitMapUsedIdx] == No) + { + ptr_bit_set[kBitMapSizeIdx] = size; + ptr_bit_set[kBitMapUsedIdx] = Yes; + + this->GetBitMapStatus(ptr_bit_set); + + UInt32 flags = this->MakeMMFlags(wr, user); + mm_map_page(ptr_bit_set, ptr_bit_set, flags); + + if (biggest_block < size) + biggest_block = size; + + return (VoidPtr)ptr_bit_set; + } + } + else if (ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) + { + ptr_bit_set[kBitMapMagIdx] = kBitMapMagic; + ptr_bit_set[kBitMapSizeIdx] = size; + ptr_bit_set[kBitMapUsedIdx] = Yes; + + this->GetBitMapStatus(ptr_bit_set); + + UInt32 flags = this->MakeMMFlags(wr, user); + mm_map_page(ptr_bit_set, ptr_bit_set, flags); + + if (biggest_block < size) + biggest_block = size; + + return (VoidPtr)ptr_bit_set; + } + + base = reinterpret_cast<VoidPtr>(reinterpret_cast<UIntPtr>(base) + ((ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) ? (size) : ptr_bit_set[kBitMapSizeIdx])); + } + + return nullptr; + } + + /// @brief Print Bitmap status + auto GetBitMapStatus(UIntPtr* ptr_bit_set) -> Void + { + if (!this->IsBitMap(ptr_bit_set)) + { + kout << "Not a BitMap: " << hex_number((UIntPtr)ptr_bit_set) << kendl; + return; + } + + kout << "Magic Number: " << hex_number(ptr_bit_set[kBitMapMagIdx]) << kendl; + kout << "Is Allocated: " << (ptr_bit_set[kBitMapUsedIdx] ? "Yes" : "No") << kendl; + kout << "Size of BitMap (B): " << number(ptr_bit_set[kBitMapSizeIdx]) << kendl; + kout << "Size of BitMap (KIB): " << number(KIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Size of BitMap (MIB): " << number(MIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Size of BitMap (GIB): " << number(GIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Size of BitMap (TIB): " << number(TIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Address Of BitMap Header: " << hex_number((UIntPtr)ptr_bit_set) << kendl; + } + }; + } // namespace Detail + + auto mm_is_bitmap(VoidPtr ptr) -> Bool + { + Detail::IBitMapProxy bitmp; + return bitmp.IsBitMap(ptr); + } + + /// @brief Allocate a new page to be used by the OS. + /// @param wr read/write bit. + /// @param user user bit. + /// @return a new bitmap allocated pointer. + auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page) -> VoidPtr + { + VoidPtr ptr_new = nullptr; + Detail::IBitMapProxy bitmp; + + ptr_new = bitmp.FindBitMap(kKernelBitMpStart, size, wr, user); + + MUST_PASS(ptr_new); + + return (UIntPtr*)ptr_new; + } + + /// @brief Free Bitmap, and mark it as absent. + /// @param ptr the pointer to free. + auto mm_free_bitmap(VoidPtr ptr) -> Bool + { + if (!ptr) + return No; + + Detail::IBitMapProxy bitmp; + Bool ret = bitmp.FreeBitMap(ptr); + + return ret; + } + } // namespace HAL +} // namespace NeOS diff --git a/dev/kernel/src/CodeMgr.cc b/dev/kernel/src/CodeMgr.cc new file mode 100644 index 00000000..c639155d --- /dev/null +++ b/dev/kernel/src/CodeMgr.cc @@ -0,0 +1,28 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/CodeMgr.h> +#include <NewKit/Utils.h> +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + /***********************************************************************************/ + /// @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 if the process was started or not. + /***********************************************************************************/ + + ProcessID rtl_create_process(rtl_main_kind main, const Char* process_name) noexcept + { + if (!process_name || + *process_name == 0) + return kProcessInvalidID; + + return UserProcessScheduler::The().Spawn(process_name, reinterpret_cast<VoidPtr>(main), nullptr); + } +} // namespace NeOS diff --git a/dev/kernel/src/Crc32.cc b/dev/kernel/src/Crc32.cc new file mode 100644 index 00000000..98821602 --- /dev/null +++ b/dev/kernel/src/Crc32.cc @@ -0,0 +1,82 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Crc32.h> + +// @file CRC32.cpp +// @brief Check sequence implementation. + +namespace NeOS +{ + /// @brief The CRC32 seed table. + UInt32 kCrcTbl[kCrcCnt] = { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, + 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, + 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, + 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, + 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, + 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, + 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, + 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, + 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, + 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, + 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, + 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, + 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, + 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, + 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, + 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, + 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, + 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, + 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, + 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, + 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, + 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, + 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, + 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, + 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, + 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, + 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, + 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, + 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, + 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, + 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, + 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, + 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, + 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, + 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, + 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, + 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, + 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, + 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, + 0xAD7D5351L}; + + /// @brief Calculate CRC32 of p + /// @param p the data to compute. + /// @param len the length of the data. + /// @return CRC32 of **p**. + UInt32 ke_calculate_crc32(const Char* p, Int32 len) noexcept + { + UInt32 crc = 0xffffffff; + + while (--len > 0) + crc = kCrcTbl[((UInt8)crc ^ *(p++))] ^ (crc >> 8); + + return ~crc; + } +} // namespace NeOS diff --git a/dev/kernel/src/CxxAbi-AMD64.cc b/dev/kernel/src/CxxAbi-AMD64.cc new file mode 100644 index 00000000..f0e57077 --- /dev/null +++ b/dev/kernel/src/CxxAbi-AMD64.cc @@ -0,0 +1,90 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __NE_AMD64__ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/CxxAbi.h> +#include <KernelKit/LPC.h> + +atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; + +uarch_t __atexit_func_count; + +/// @brief dynamic shared object Handle. +NeOS::UIntPtr __dso_handle; + +EXTERN_C NeOS::Void __cxa_pure_virtual(void* self) +{ + kout << "object: " << NeOS::number(reinterpret_cast<NeOS::UIntPtr>(self)); + kout << ", has unimplemented virtual functions.\r"; +} + +EXTERN_C void ___chkstk_ms(void) +{ +} + +EXTERN_C int atexit(void (*f)(void*), void* arg, void* dso) +{ + if (__atexit_func_count >= kAtExitMacDestructors) + return 1; + + __atexit_funcs[__atexit_func_count].destructor_func = f; + __atexit_funcs[__atexit_func_count].obj_ptr = arg; + __atexit_funcs[__atexit_func_count].dso_handle = dso; + + __atexit_func_count++; + + return 0; +} + +EXTERN_C void __cxa_finalize(void* f) +{ + uarch_t i = __atexit_func_count; + if (!f) + { + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + }; + } + + return; + } + + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + __atexit_funcs[i].destructor_func = 0; + }; + } +} + +namespace cxxabiv1 +{ + EXTERN_C int __cxa_guard_acquire(__guard* g) + { + (void)g; + return 0; + } + + EXTERN_C int __cxa_guard_release(__guard* g) + { + *(char*)g = 1; + return 0; + } + + EXTERN_C void __cxa_guard_abort(__guard* g) + { + (void)g; + } +} // namespace cxxabiv1 + +#endif // ifdef __NE_AMD64__ diff --git a/dev/kernel/src/CxxAbi-ARM64.cc b/dev/kernel/src/CxxAbi-ARM64.cc new file mode 100644 index 00000000..b52be160 --- /dev/null +++ b/dev/kernel/src/CxxAbi-ARM64.cc @@ -0,0 +1,107 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __NE_ARM64__ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/CxxAbi.h> +#include <KernelKit/LPC.h> + +atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; + +uarch_t __atexit_func_count; + +/// @brief dynamic shared object Handle. +NeOS::UIntPtr __dso_handle; + +EXTERN_C void __chkstk(void) +{ +} + +EXTERN_C int atexit(void (*f)(void*), void* arg, void* dso) +{ + if (__atexit_func_count >= kAtExitMacDestructors) + return 1; + + __atexit_funcs[__atexit_func_count].destructor_func = f; + __atexit_funcs[__atexit_func_count].obj_ptr = arg; + __atexit_funcs[__atexit_func_count].dso_handle = dso; + + __atexit_func_count++; + + return 0; +} + +EXTERN_C void __cxa_finalize(void* f) +{ + uarch_t i = __atexit_func_count; + if (!f) + { + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + }; + } + + return; + } + + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + __atexit_funcs[i].destructor_func = 0; + }; + } +} + +namespace cxxabiv1 +{ + EXTERN_C int __cxa_guard_acquire(__guard* g) + { + (void)g; + return 0; + } + + EXTERN_C int __cxa_guard_release(__guard* g) + { + *(char*)g = 1; + return 0; + } + + EXTERN_C void __cxa_guard_abort(__guard* g) + { + (void)g; + } +} // namespace cxxabiv1 + +EXTERN_C NeOS::Void _purecall(void* self) +{ + kout << "object: " << NeOS::number(reinterpret_cast<NeOS::UIntPtr>(self)); + kout << ", has unimplemented virtual functions.\r"; +} + +EXTERN_C NeOS::Void _Init_thread_footer(NeOS::Int* thread_obj) +{ + NE_UNUSED(thread_obj); +} + +EXTERN_C NeOS::Void _Init_thread_epoch(NeOS::Void) +{ + NE_UNUSED(0); +} + +EXTERN_C NeOS::Void _Init_thread_header(NeOS::Int* thread_obj) +{ + NE_UNUSED(0); +} + +EXTERN_C NeOS::Int _tls_index = 0UL; + +#endif // ifdef __NE_ARM64__ diff --git a/dev/kernel/src/Defines.cc b/dev/kernel/src/Defines.cc new file mode 100644 index 00000000..c29afcf4 --- /dev/null +++ b/dev/kernel/src/Defines.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Defines.h> diff --git a/dev/kernel/src/DeviceMgr.cc b/dev/kernel/src/DeviceMgr.cc new file mode 100644 index 00000000..760d17d9 --- /dev/null +++ b/dev/kernel/src/DeviceMgr.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DeviceMgr.h> diff --git a/dev/kernel/src/DriveMgr+IO.cc b/dev/kernel/src/DriveMgr+IO.cc new file mode 100644 index 00000000..8381087f --- /dev/null +++ b/dev/kernel/src/DriveMgr+IO.cc @@ -0,0 +1,96 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DriveMgr.h> +#include <KernelKit/FileMgr.h> + +/************************************************************* + * + * File: DriveMgr+IO.cc + * Purpose: Filesystem to mountpoint interface. + * Date: 3/26/24 + * + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + *************************************************************/ + +/// Useful macros. + +#define rtl_nefs_write(DRV, TRAITS, MP) (MP->DRV()).fOutput(TRAITS) +#define rtl_nefs_read(DRV, TRAITS, MP) (MP->DRV()).fInput(TRAITS) + +namespace NeOS +{ + /// @brief Read from newfs disk. + /// @param Mnt mounted interface. + /// @param DrvTrait drive info + /// @param DrvIndex drive index. + /// @return + Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) + { + if (!Mnt) + return 1; + + DrvTrait.fPacket.fPacketGood = false; + + switch (DrvIndex) + { + case MountpointInterface::kDriveIndexA: { + rtl_nefs_read(A, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexB: { + rtl_nefs_read(B, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexC: { + rtl_nefs_read(C, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexD: { + rtl_nefs_read(D, DrvTrait.fPacket, Mnt); + break; + } + } + + return DrvTrait.fPacket.fPacketGood; + } + + /// @brief Write to newfs disk. + /// @param Mnt mounted interface. + /// @param DrvTrait drive info + /// @param DrvIndex drive index. + /// @return + Int32 fs_ifs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) + { + if (!Mnt) + return 1; + + DrvTrait.fPacket.fPacketGood = false; + + switch (DrvIndex) + { + case MountpointInterface::kDriveIndexA: { + rtl_nefs_write(A, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexB: { + rtl_nefs_write(B, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexC: { + rtl_nefs_write(C, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexD: { + rtl_nefs_write(D, DrvTrait.fPacket, Mnt); + break; + } + } + + return DrvTrait.fPacket.fPacketGood; + } +} // namespace NeOS
\ No newline at end of file diff --git a/dev/kernel/src/DriveMgr.cc b/dev/kernel/src/DriveMgr.cc new file mode 100644 index 00000000..039f7e08 --- /dev/null +++ b/dev/kernel/src/DriveMgr.cc @@ -0,0 +1,235 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/DriveMgr.h> +#include <NewKit/Utils.h> +#include <FirmwareKit/EPM.h> +#include <modules/ATA/ATA.h> +#include <modules/AHCI/AHCI.h> +#include <modules/NVME/NVME.h> + +/***********************************************************************************/ +/// @file DriveMgr.cc +/// @brief Drive Manager of kernel. +/***********************************************************************************/ + +namespace NeOS +{ +#if defined(__ATA_PIO__) || defined(__ATA_DMA__) + STATIC UInt16 kATAIO = 0U; + STATIC UInt8 kATAMaster = 0U; +#endif + +#if defined(__AHCI__) + STATIC UInt16 kAHCIPortsImplemented = 0UL; +#endif + + /// @brief reads from an ATA drive. + /// @param pckt Packet structure (fPacketContent must be non null) + /// @return + Void io_drv_input(DriveTrait::DrivePacket pckt) + { +#ifdef __AHCI__ + drv_std_read(pckt.fPacketLba, (Char*)pckt.fPacketContent, kAHCISectorSize, pckt.fPacketSize); +#elif defined(__ATA_PIO__) || defined(__ATA_DMA__) + drv_std_read(pckt.fPacketLba, kATAIO, kATAMaster, (Char*)pckt.fPacketContent, kATASectorSize, pckt.fPacketSize); +#endif + } + + /// @brief Writes to an ATA drive. + /// @param pckt the packet to write. + /// @return + Void io_drv_output(DriveTrait::DrivePacket pckt) + { + if (pckt.fPacketReadOnly) + { + pckt.fPacketGood = NO; + return; + } + +#ifdef __AHCI__ + drv_std_write(pckt.fPacketLba, (Char*)pckt.fPacketContent, kAHCISectorSize, pckt.fPacketSize); +#elif defined(__ATA_PIO__) || defined(__ATA_DMA__) + drv_std_write(pckt.fPacketLba, kATAIO, kATAMaster, (Char*)pckt.fPacketContent, kATASectorSize, pckt.fPacketSize); +#endif + } + + /// @brief Executes a disk check on the ATA drive. + /// @param pckt the packet to read. + /// @return + Void io_drv_init(DriveTrait::DrivePacket pckt) + { +#if defined(__ATA_PIO__) || defined(__ATA_DMA__) + kATAMaster = 0; + kATAIO = 0; + + kATAMaster = YES; + kATAIO = ATA_PRIMARY_IO; + + if (drv_std_init(kATAIO, kATAMaster, kATAIO, kATAMaster)) + { + pckt.fPacketGood = YES; + return; + } + + kATAMaster = NO; + kATAIO = ATA_SECONDARY_IO; + + if (!drv_std_init(kATAIO, kATAMaster, kATAIO, kATAMaster)) + { + pckt.fPacketGood = YES; + return; + } + + pckt.fPacketGood = YES; +#elif defined(__AHCI__) + kAHCIPortsImplemented = 0; + + if (!drv_std_init(kAHCIPortsImplemented)) + { + return; + } + + pckt.fPacketGood = YES; +#endif // if defined(__ATA_PIO__) || defined (__ATA_DMA__) + } + +/// @brief Gets the drive kind (ATA, SCSI, AHCI...) +/// @param void no arguments. +/// @return no arguments. +#ifdef __ATA_PIO__ + const Char* io_drv_kind(Void) + { + return "ATA-PIO"; + } +#endif +#ifdef __ATA_DMA__ + const Char* io_drv_kind(Void) + { + return "ATA-DMA"; + } +#endif +#ifdef __AHCI__ + const Char* io_drv_kind(Void) + { + return "AHCI"; + } +#endif +#ifdef __NE_MINIMAL_OS__ + const Char* io_drv_kind(Void) + { + return "Not Loaded"; + } +#endif + + /// @brief Unimplemented drive function. + /// @param pckt the packet to read. + Void io_drv_unimplemented(DriveTrait::DrivePacket pckt) noexcept + { + NE_UNUSED(pckt); + } + + /// @brief Makes a new drive. + /// @return the new blank drive. + DriveTrait io_construct_blank_drive() noexcept + { + DriveTrait trait; + + constexpr auto kBlankDrive = "/media/blank/"; + + rt_copy_memory((VoidPtr)kBlankDrive, trait.fName, rt_string_len(kBlankDrive)); + trait.fKind = kInvalidDrive; + + trait.fInput = io_drv_unimplemented; + trait.fOutput = io_drv_unimplemented; + trait.fVerify = io_drv_unimplemented; + trait.fInit = io_drv_unimplemented; + trait.fDriveKind = io_drv_kind; + + kout << "Construct: " << trait.fName << "\r"; + + return trait; + } + + namespace Detail + { + Void io_detect_drive(DriveTrait& trait) + { + trait.fInit(trait.fPacket); + + EPM_PART_BLOCK block_struct; + + trait.fPacket.fPacketLba = kEPMBootBlockLba; + trait.fPacket.fPacketSize = sizeof(EPM_PART_BLOCK); + trait.fPacket.fPacketContent = &block_struct; + + rt_copy_memory((VoidPtr) "fs/detect-packet", trait.fPacket.fPacketMime, + rt_string_len("fs/detect-packet")); + + trait.fInput(trait.fPacket); + + if (rt_string_cmp(((EPM_PART_BLOCK*)trait.fPacket.fPacketContent)->Magic, kEPMMagic, kEPMMagicLength) == 0) + { + trait.fPacket.fPacketReadOnly = NO; + trait.fKind = kMassStorageDrive | kEPMDrive; + + kout << "Disk is EPM.\r"; + + trait.fSectorSz = block_struct.SectorSz; + trait.fLbaEnd = block_struct.LbaEnd; + trait.fLbaStart = block_struct.LbaStart; + } + else + { + trait.fPacket.fPacketReadOnly = YES; + trait.fKind = kMassStorageDrive | kUnformattedDrive | kReadOnlyDrive; + + if (block_struct.Name[0] == 0 || + !rt_is_alnum(block_struct.Name[0])) + { + kout << "Disk partition is empty (Read Only)\r"; + } + else + { + kout << "Scheme Found: " << block_struct.Name << kendl; + } + } + + rt_copy_memory((VoidPtr) "*/*", trait.fPacket.fPacketMime, + rt_string_len("*/*")); + + trait.fPacket.fPacketLba = 0; + trait.fPacket.fPacketSize = 0UL; + trait.fPacket.fPacketContent = nullptr; + } + } // namespace Detail + + /// @brief Fetches the main drive. + /// @return the new drive. (returns kEPMDrive if EPM formatted) + DriveTrait io_construct_main_drive() noexcept + { + DriveTrait trait; + + constexpr auto kMainDrive = "/media/sda/"; + + rt_copy_memory((VoidPtr)kMainDrive, trait.fName, rt_string_len(kMainDrive)); + + MUST_PASS(trait.fName[0] != 0); + + trait.fVerify = io_drv_unimplemented; + trait.fOutput = io_drv_output; + trait.fInput = io_drv_input; + trait.fInit = io_drv_init; + trait.fDriveKind = io_drv_kind; + + kout << "Detecting partition scheme of: " << trait.fName << ".\r"; + + Detail::io_detect_drive(trait); + + return trait; + } +} // namespace NeOS diff --git a/dev/kernel/src/ErrorOr.cc b/dev/kernel/src/ErrorOr.cc new file mode 100644 index 00000000..7a55715c --- /dev/null +++ b/dev/kernel/src/ErrorOr.cc @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/ErrorOr.h> + +/***********************************************************************************/ +/// @file ErrorOr.cc /// +/// @brief ErrorOr container class. /// +/***********************************************************************************/ diff --git a/dev/kernel/src/FS/HeFS.cc b/dev/kernel/src/FS/HeFS.cc new file mode 100644 index 00000000..7615ed77 --- /dev/null +++ b/dev/kernel/src/FS/HeFS.cc @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __FSKIT_INCLUDES_HeFS__ + +#include <modules/AHCI/AHCI.h> +#include <modules/ATA/ATA.h> +#include <modules/Flash/Flash.h> +#include <FSKit/HeFS.h> +#include <KernelKit/LPC.h> +#include <NewKit/Crc32.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/KString.h> +#include <NewKit/Utils.h> +#include <FirmwareKit/EPM.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/User.h> + +#endif // ifdef __FSKIT_INCLUDES_HeFS__ diff --git a/dev/kernel/src/FS/NeFS+FileMgr.cc b/dev/kernel/src/FS/NeFS+FileMgr.cc new file mode 100644 index 00000000..0ac6384d --- /dev/null +++ b/dev/kernel/src/FS/NeFS+FileMgr.cc @@ -0,0 +1,245 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/FileMgr.h> +#include <KernelKit/MemoryMgr.h> + +#ifndef __NE_MINIMAL_OS__ +#ifdef __FSKIT_INCLUDES_NEFS__ + +/// @brief NeFS File manager. +/// BUGS: 0 + +namespace NeOS +{ + /// @brief C++ constructor + NeFileSystemMgr::NeFileSystemMgr() + { + NeFileSystemParser* mParser = new NeFileSystemParser(); + MUST_PASS(mParser); + + kout << "We are done allocating NeFileSystemParser...\r"; + } + + NeFileSystemMgr::~NeFileSystemMgr() + { + if (mParser) + { + kout << "Destroying NeFileSystemParser...\r"; + mm_delete_class(&mParser); + } + } + + /// @brief Removes a node from the filesystem. + /// @param path The filename + /// @return If it was deleted or not. + bool NeFileSystemMgr::Remove(_Input const Char* path) + { + if (path == nullptr || *path == 0) + return false; + + return mParser->RemoveCatalog(path); + } + + /// @brief Creates a node with the specified. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::Create(_Input const Char* path) + { + return node_cast(mParser->CreateCatalog(path)); + } + + /// @brief Creates a node with is a directory. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::CreateDirectory(const Char* path) + { + return node_cast(mParser->CreateCatalog(path, 0, kNeFSCatalogKindDir)); + } + + /// @brief Creates a node with is a alias. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::CreateAlias(const Char* path) + { + return node_cast(mParser->CreateCatalog(path, 0, kNeFSCatalogKindAlias)); + } + + /// @brief Creates a node with is a page file. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::CreateSwapFile(const Char* path) + { + return node_cast(mParser->CreateCatalog(path, 0, kNeFSCatalogKindPage)); + } + + /// @brief Gets the root directory. + /// @return + const Char* NeFileSystemHelper::Root() + { + return kNeFSRoot; + } + + /// @brief Gets the up-dir directory. + /// @return + const Char* NeFileSystemHelper::UpDir() + { + return kNeFSUpDir; + } + + /// @brief Gets the separator character. + /// @return + const Char NeFileSystemHelper::Separator() + { + return kNeFSSeparator; + } + + /// @brief Gets the metafile character. + /// @return + const Char NeFileSystemHelper::MetaFile() + { + return kNeFSMetaFilePrefix; + } + + /// @brief Opens a new file. + /// @param path + /// @param r + /// @return + _Output NodePtr NeFileSystemMgr::Open(_Input const Char* path, _Input const Char* r) + { + if (!path || *path == 0) + return nullptr; + + if (!r || *r == 0) + return nullptr; + + auto catalog = mParser->GetCatalog(path); + + return node_cast(catalog); + } + + /// @brief Writes to a catalog's fork. + /// @param node the node ptr. + /// @param data the data. + /// @param flags the size. + /// @return + Void NeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, _Input SizeT size) + { + if (!node) + return; + if (!size) + return; + + constexpr auto kDataForkName = kNeFSDataFork; + this->Write(kDataForkName, node, data, flags, size); + } + + /// @brief Read from filesystem fork. + /// @param node the catalog node. + /// @param flags the flags with it. + /// @param sz the size to read. + /// @return + _Output VoidPtr NeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) + { + if (!node) + return nullptr; + if (!size) + return nullptr; + + constexpr auto kDataForkName = kNeFSDataFork; + return this->Read(kDataForkName, node, flags, size); + } + + Void NeFileSystemMgr::Write(_Input const Char* name, + _Input NodePtr node, + _Input VoidPtr data, + _Input Int32 flags, + _Input SizeT size) + { + if (!size || + size > kNeFSForkSize) + return; + + if (!data) + return; + + NE_UNUSED(flags); + + if ((reinterpret_cast<NEFS_CATALOG_STRUCT*>(node))->Kind == kNeFSCatalogKindFile) + mParser->WriteCatalog(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node)->Name, (flags & kFileFlagRsrc ? true : false), data, size, + name); + } + + _Output VoidPtr NeFileSystemMgr::Read(_Input const Char* name, + _Input NodePtr node, + _Input Int32 flags, + _Input SizeT sz) + { + if (sz > kNeFSForkSize) + return nullptr; + + if (!sz) + return nullptr; + + NE_UNUSED(flags); + + if ((reinterpret_cast<NEFS_CATALOG_STRUCT*>(node))->Kind == kNeFSCatalogKindFile) + return mParser->ReadCatalog(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node), (flags & kFileFlagRsrc ? true : false), sz, + name); + + return nullptr; + } + + /// @brief Seek from Catalog. + /// @param node + /// @param off + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output Bool NeFileSystemMgr::Seek(NodePtr node, SizeT off) + { + if (!node || off == 0) + return false; + + return mParser->Seek(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node), off); + } + + /// @brief Tell where the catalog is. + /// @param node + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output SizeT NeFileSystemMgr::Tell(NodePtr node) + { + if (!node) + return kNPos; + + return mParser->Tell(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node)); + } + + /// @brief Rewinds the catalog. + /// @param node + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output Bool NeFileSystemMgr::Rewind(NodePtr node) + { + if (!node) + return false; + + return this->Seek(node, 0); + } + + /// @brief Returns the filesystem parser. + /// @return the Filesystem parser class. + _Output NeFileSystemParser* NeFileSystemMgr::GetParser() noexcept + { + return mParser; + } +} // namespace NeOS + +#endif // ifdef __FSKIT_INCLUDES_NEFS__ +#endif // ifndef __NE_MINIMAL_OS__ diff --git a/dev/kernel/src/FS/NeFS.cc b/dev/kernel/src/FS/NeFS.cc new file mode 100644 index 00000000..30d4fb85 --- /dev/null +++ b/dev/kernel/src/FS/NeFS.cc @@ -0,0 +1,1065 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __FSKIT_INCLUDES_NEFS__ + +#include <FSKit/NeFS.h> +#include <FirmwareKit/EPM.h> + +#include <modules/AHCI/AHCI.h> +#include <modules/ATA/ATA.h> +#include <modules/MFlash/MFlash.h> +#include <KernelKit/LPC.h> +#include <NewKit/Crc32.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/KString.h> +#include <NewKit/Utils.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/User.h> +#include <KernelKit/DriveMgr.h> + +using namespace NeOS; + +#ifdef __NE_NO_BUILTIN__ +/***********************************************************************************/ +/** + Define those external symbols, to make the editor shutup +*/ +/***********************************************************************************/ + +/***********************************************************************************/ +/// @brief get sector count. +/***********************************************************************************/ +NeOS::SizeT drv_get_sector_count(); + +/***********************************************************************************/ +/// @brief get device size. +/***********************************************************************************/ +NeOS::SizeT drv_get_size(); + +#endif + +///! BUGS: 0 + +/***********************************************************************************/ +/// This file implements the New extended File System. +/// New extended File System implements a B-Tree based algortihm. +/// / +/// /Path1/ /ath2/ +/// /readme.rtf /ListContents.pef /readme.lnk <-- symlink. +/// /Path1/readme.rtf +/***********************************************************************************/ + +STATIC MountpointInterface kMountpoint; + +/***********************************************************************************/ +/// @brief Creates a new fork inside the New filesystem partition. +/// @param catalog it's catalog +/// @param the_fork the fork itself. +/// @return the fork +/***********************************************************************************/ +_Output BOOL NeFileSystemParser::CreateFork(_Input NEFS_FORK_STRUCT& the_fork) +{ + if (the_fork.ForkName[0] != 0 && + the_fork.CatalogName[0] != 0 && + the_fork.DataSize > 0) + { + auto catalog = this->GetCatalog(the_fork.CatalogName); + + if (!catalog) + return NO; + + Lba lba = catalog->DataFork; + + kout << "Fork LBA: " << hex_number(lba) << kendl; + + if (lba < kNeFSCatalogStartAddress) + return NO; + + auto& drv = kMountpoint.A(); + + Lba lba_prev = lba; + + NEFS_FORK_STRUCT prev_fork; + NEFS_FORK_STRUCT cur_fork; + + /// do not check for anything. Loop until we get what we want, that is a free fork zone. + while (drv.fPacket.fPacketGood) + { + drv.fPacket.fPacketLba = lba; + drv.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &cur_fork; + + drv.fInput(drv.fPacket); + + kout << "Next fork: " << hex_number(cur_fork.NextSibling) << kendl; + + if (cur_fork.Flags & kNeFSFlagCreated) + { + kout << "Error: Fork does exists.\r"; + + /// sanity check. + if (KStringBuilder::Equals(cur_fork.ForkName, the_fork.ForkName) && + KStringBuilder::Equals(cur_fork.CatalogName, the_fork.CatalogName)) + break; + + lba_prev = lba; + lba = cur_fork.NextSibling; + + prev_fork = cur_fork; + } + else + { + /// This is a check that we have, in order to link the previous fork + /// entry. + if (lba >= kNeFSCatalogStartAddress) + { + drv.fPacket.fPacketLba = lba_prev; + drv.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &prev_fork; + + prev_fork.NextSibling = lba; + + /// write to disk. + drv.fOutput(drv.fPacket); + } + + break; + } + } + + the_fork.Flags |= kNeFSFlagCreated; + the_fork.DataOffset = lba - sizeof(NEFS_FORK_STRUCT); + the_fork.PreviousSibling = lba_prev; + the_fork.NextSibling = the_fork.DataOffset - the_fork.DataSize; + + drv.fPacket.fPacketLba = lba; + drv.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &the_fork; + + kout << "Allocating fork block...\r"; + + // drv.fOutput(drv.fPacket); + + fs_ifs_write(&kMountpoint, drv, MountpointInterface::kDriveIndexA); + + /// log what we have now. + kout << "Fork offset is at: " << hex_number(the_fork.DataOffset) + << kendl; + + kout << "Wrote fork metadata at: " << hex_number(lba) << kendl; + + return YES; + } + + return NO; +} + +/***********************************************************************************/ +/// @brief Find fork inside filesystem. +/// @param catalog the catalog. +/// @param name the fork name. +/// @return the newly found fork. +/***********************************************************************************/ +_Output NEFS_FORK_STRUCT* NeFileSystemParser::FindFork(_Input NEFS_CATALOG_STRUCT* catalog, + _Input const Char* name, + _Input Boolean is_data) +{ + auto& drive = kMountpoint.A(); + NEFS_FORK_STRUCT* the_fork = nullptr; + + Lba lba = is_data ? catalog->DataFork : catalog->ResourceFork; + + while (lba != 0) + { + drive.fPacket.fPacketLba = lba; + drive.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drive.fPacket.fPacketContent = (VoidPtr)the_fork; + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, 16); + + if (auto res = + fs_ifs_read(&kMountpoint, drive, this->mDriveIndex); + res) + { + switch (res) + { + case 1: + err_global_get() = kErrorDiskReadOnly; + break; + case 2: + err_global_get() = kErrorDiskIsFull; + break; + case 3: + err_global_get() = kErrorNoSuchDisk; + break; + + default: + break; + } + return nullptr; + } + + if (KStringBuilder::Equals(the_fork->ForkName, name)) + { + break; + } + + lba = the_fork->NextSibling; + } + + return the_fork; +} + +/***********************************************************************************/ +/// @brief Simpler factory to create a catalog (assumes you want to create a +/// file.) +/// @param name +/// @return catalog pointer. +/***********************************************************************************/ +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::CreateCatalog(_Input const Char* name) +{ + return this->CreateCatalog(name, 0, kNeFSCatalogKindFile); +} + +/***********************************************************************************/ +/// @brief Creates a new catalog into the disk. +/// @param name the catalog name. +/// @param flags the flags of the catalog. +/// @param kind the catalog kind. +/// @return catalog pointer. +/***********************************************************************************/ +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::CreateCatalog(_Input const Char* name, + _Input const Int32& flags, + _Input const Int32& kind) +{ + kout << "CreateCatalog(*...*)\r"; + + Lba out_lba = 0UL; + + kout << "Checking for path separator...\r"; + + /// a directory should have a slash in the end. + if (kind == kNeFSCatalogKindDir && + name[rt_string_len(name) - 1] != NeFileSystemHelper::Separator()) + return nullptr; + + /// a file shouldn't have a slash in the end. + if (kind != kNeFSCatalogKindDir && + name[rt_string_len(name) - 1] == NeFileSystemHelper::Separator()) + return nullptr; + + NEFS_CATALOG_STRUCT* catalog_copy = this->FindCatalog(name, out_lba); + + if (catalog_copy) + { + kout << "Catalog already exists: " << name << ".\r"; + err_global_get() = kErrorFileExists; + + delete catalog_copy; + catalog_copy = nullptr; + + return nullptr; + } + + Char parent_name[kNeFSCatalogNameLen] = {0}; + + for (SizeT indexName = 0UL; indexName < rt_string_len(name); ++indexName) + { + parent_name[indexName] = name[indexName]; + } + + if (*parent_name == 0) + { + kout << "Parent name is NUL.\r"; + err_global_get() = kErrorFileNotFound; + return nullptr; + } + + /// Locate parent catalog, to then allocate right after it. + + for (SizeT index_fill = 0; index_fill < rt_string_len(name); ++index_fill) + { + parent_name[index_fill] = name[index_fill]; + } + + SizeT index_reverse_copy = rt_string_len(parent_name); + + // zero character it. + parent_name[--index_reverse_copy] = 0; + + // mandatory / character, zero it. + parent_name[--index_reverse_copy] = 0; + + while (parent_name[index_reverse_copy] != NeFileSystemHelper::Separator()) + { + parent_name[index_reverse_copy] = 0; + --index_reverse_copy; + } + + NEFS_CATALOG_STRUCT* catalog = this->FindCatalog(parent_name, out_lba); + + auto& drive = kMountpoint.A(); + + constexpr auto kNeFSCatalogPadding = 4; + + if (catalog && catalog->Kind == kNeFSCatalogKindFile) + { + kout << "Parent is a file.\r"; + delete catalog; + + return nullptr; + } + else if (!catalog) + { + Char part_block[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + drive.fPacket.fPacketContent = part_block; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + NEFS_ROOT_PARTITION_BLOCK* blk_nefs = (NEFS_ROOT_PARTITION_BLOCK*)part_block; + out_lba = blk_nefs->StartCatalog; + } + + if (drive.fPacket.fPacketReadOnly) + return nullptr; + + NEFS_CATALOG_STRUCT* child_catalog = new NEFS_CATALOG_STRUCT(); + + child_catalog->Checksum = 0; + child_catalog->ResourceForkSize = 0UL; + child_catalog->DataForkSize = 0UL; + child_catalog->CatalogFlags = kNeFSStatusUnlocked; + child_catalog->NextSibling = out_lba; + child_catalog->PrevSibling = out_lba; + child_catalog->Kind = kind; + child_catalog->Flags |= kNeFSFlagCreated; + child_catalog->CatalogFlags = flags; + + SizeT i = rt_string_len(name); + + // get rid pf \0 + --i; + + if (kind == kNeFSCatalogKindDir) + --i; + + while (name[i] != '/') + --i; + + rt_copy_memory((VoidPtr)(name + i), (VoidPtr)child_catalog->Name, + rt_string_len(name)); + + NEFS_CATALOG_STRUCT temporary_catalog{}; + + Lba start_free = out_lba; + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + Char buf_part_block[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + drive.fPacket.fPacketContent = buf_part_block; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + NEFS_ROOT_PARTITION_BLOCK* part_block = (NEFS_ROOT_PARTITION_BLOCK*)buf_part_block; + + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fInput(drive.fPacket); + + if (part_block->FreeCatalog < 1) + { + delete child_catalog; + child_catalog = nullptr; + + return nullptr; + } + + kout << "Start finding catalog to allocate or empty space...\r"; + + while (start_free >= part_block->StartCatalog) + { + // ========================== // + // Allocate catalog now... + // ========================== // + if ((temporary_catalog.Flags & kNeFSFlagCreated) == 0) + { + child_catalog->NextSibling = + start_free + (sizeof(NEFS_CATALOG_STRUCT) * kNeFSCatalogPadding); + + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fOutput(drive.fPacket); + + child_catalog->DataFork = part_block->DiskSize - start_free; + child_catalog->ResourceFork = child_catalog->DataFork; + + drive.fPacket.fPacketContent = child_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fOutput(drive.fPacket); + + // Get NeFS partition's block. + + drive.fPacket.fPacketContent = buf_part_block; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + part_block->FreeSectors -= 1; + part_block->CatalogCount += 1; + part_block->FreeCatalog -= 1; + + drive.fOutput(drive.fPacket); + + kout << "Create new catalog with flags: " + << hex_number(child_catalog->Flags) << kendl; + kout << "Create new catalog with name: " << child_catalog->Name + << kendl; + + delete catalog; + catalog = nullptr; + + NEFS_CATALOG_STRUCT* found_catalog = new NEFS_CATALOG_STRUCT(); + rt_copy_memory(&temporary_catalog, found_catalog, sizeof(NEFS_CATALOG_STRUCT)); + + return found_catalog; + } + else if ((temporary_catalog.Flags & kNeFSFlagCreated) && + KStringBuilder::Equals(temporary_catalog.Name, name)) + { + rt_copy_memory(&temporary_catalog, child_catalog, sizeof(NEFS_CATALOG_STRUCT)); + + return child_catalog; + } + + start_free = start_free + (sizeof(NEFS_CATALOG_STRUCT) * kNeFSCatalogPadding); + + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fInput(drive.fPacket); + } + + delete catalog; + return nullptr; +} + +/// @brief Make a EPM+NeFS drive out of the disk. +/// @param drive The drive to write on. +/// @return If it was sucessful, see err_global_get(). +bool NeFileSystemParser::Format(_Input _Output DriveTrait* drive, _Input const Lba endLba, _Input const Int32 flags, const Char* part_name) +{ + if (*part_name == 0 || + endLba == 0) + return false; + + // verify disk. + drive->fVerify(drive->fPacket); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + // if disk isn't good, then error out. + if (false == drive->fPacket.fPacketGood) + { + err_global_get() = kErrorDiskIsCorrupted; + return false; + } + + Char fs_buf[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + Lba start = kNeFSRootCatalogStartAddress; + + drive->fPacket.fPacketContent = fs_buf; + drive->fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive->fPacket.fPacketLba = start; + + drive->fInput(drive->fPacket); + + if (flags & kNeFSPartitionTypeBoot) + { + // make it bootable when needed. + Char buf_epm[kNeFSSectorSz] = {0}; + + EPM_PART_BLOCK* epm_boot = (EPM_PART_BLOCK*)buf_epm; + + // Write a new EPM entry. + + constexpr auto kFsName = "NeFS"; + constexpr auto kBlockName = "ZkaOS:"; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(kFsName)), epm_boot->Fs, rt_string_len(kFsName)); + + epm_boot->FsVersion = kNeFSVersionInteger; + epm_boot->LbaStart = start; + epm_boot->SectorSz = kNeFSSectorSz; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(kBlockName)), epm_boot->Name, rt_string_len(kBlockName)); + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(kEPMMagic)), epm_boot->Magic, rt_string_len(kEPMMagic)); + + Lba outEpmLba = kEPMBootBlockLba; + + Char buf[kNeFSSectorSz]; + + Lba prevStart = 0; + SizeT cnt = 0; + + while (drive->fPacket.fPacketGood) + { + drive->fPacket.fPacketContent = buf; + drive->fPacket.fPacketSize = sizeof(EPM_PART_BLOCK); + drive->fPacket.fPacketLba = outEpmLba; + + drive->fInput(drive->fPacket); + + if (buf[0] == 0) + { + epm_boot->LbaStart = prevStart; + + if (epm_boot->LbaStart) + epm_boot->LbaStart = outEpmLba; + + epm_boot->LbaEnd = endLba; + epm_boot->NumBlocks = cnt; + + drive->fPacket.fPacketContent = buf_epm; + drive->fPacket.fPacketSize = sizeof(EPM_PART_BLOCK); + drive->fPacket.fPacketLba = outEpmLba; + + drive->fOutput(drive->fPacket); + + break; + } + else + { + prevStart = ((EPM_PART_BLOCK*)buf)->LbaStart + ((EPM_PART_BLOCK*)buf)->LbaEnd; + } + + outEpmLba += sizeof(EPM_PART_BLOCK); + ++cnt; + } + } + + // disk isnt faulty and data has been fetched. + while (drive->fPacket.fPacketGood) + { + NEFS_ROOT_PARTITION_BLOCK* part_block = (NEFS_ROOT_PARTITION_BLOCK*)fs_buf; + + // check for an empty partition here. + if (part_block->PartitionName[0] == 0 && + rt_string_cmp(part_block->Ident, kNeFSIdent, kNeFSIdentLen)) + { + // partition is free and valid. + + part_block->Version = kNeFSVersionInteger; + + const auto kNeFSUntitledHD = part_name; + + rt_copy_memory((VoidPtr)kNeFSIdent, (VoidPtr)part_block->Ident, + kNeFSIdentLen); + + rt_copy_memory((VoidPtr)kNeFSUntitledHD, (VoidPtr)part_block->PartitionName, + rt_string_len(kNeFSUntitledHD)); + + SizeT catalogCount = 0UL; + + SizeT sectorCount = drv_get_sector_count(); + SizeT diskSize = drv_get_size(); + + part_block->Kind = kNeFSPartitionTypeStandard; + part_block->StartCatalog = kNeFSCatalogStartAddress; + part_block->Flags = kNeFSPartitionTypeStandard; + part_block->CatalogCount = sectorCount / sizeof(NEFS_CATALOG_STRUCT); + part_block->FreeSectors = sectorCount / sizeof(NEFS_CATALOG_STRUCT); + part_block->SectorCount = sectorCount; + part_block->DiskSize = diskSize; + part_block->FreeCatalog = sectorCount / sizeof(NEFS_CATALOG_STRUCT); + + drive->fPacket.fPacketContent = fs_buf; + drive->fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive->fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive->fOutput(drive->fPacket); + + kout << "drive kind: " << drive->fDriveKind() << kendl; + + kout << "partition name: " << part_block->PartitionName << kendl; + kout << "start: " << hex_number(part_block->StartCatalog) << kendl; + kout << "number of catalogs: " << hex_number(part_block->CatalogCount) << kendl; + kout << "free catalog: " << hex_number(part_block->FreeCatalog) << kendl; + kout << "free sectors: " << hex_number(part_block->FreeSectors) << kendl; + kout << "sector size: " << hex_number(part_block->SectorSize) << kendl; + + // write the root catalog. + this->CreateCatalog(kNeFSRoot, 0, kNeFSCatalogKindDir); + + return true; + } + + kout << "partition block already exists.\r"; + + start += part_block->DiskSize; + + drive->fPacket.fPacketContent = fs_buf; + drive->fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive->fPacket.fPacketLba = start; + + drive->fInput(drive->fPacket); + } + + return false; +} + +/// @brief Writes the data fork into a specific catalog. +/// @param catalog the catalog itself +/// @param data the data. +/// @return if the catalog w rote the contents successfully. +bool NeFileSystemParser::WriteCatalog(_Input const Char* catalog_name, Bool is_rsrc_fork, _Input VoidPtr data, _Input SizeT size_of_data, _Input const Char* fork_name) +{ + if (size_of_data < 1) + return No; + + auto buf = new UInt8[size_of_data]; + rt_set_memory(buf, 0, size_of_data); + + rt_copy_memory(data, buf, size_of_data); + + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + auto catalog = this->GetCatalog(catalog_name); + + if (!catalog) + { + delete[] buf; + buf = nullptr; + return NO; + } + + auto startFork = (!is_rsrc_fork) ? catalog->DataFork + : catalog->ResourceFork; + + delete catalog; + catalog = nullptr; + + NEFS_FORK_STRUCT* fork_data_input = new NEFS_FORK_STRUCT(); + NEFS_FORK_STRUCT prev_fork{}; + + kout << hex_number(startFork) << kendl; + + // sanity check of the fork position as the condition to run the loop. + while (startFork >= kNeFSCatalogStartAddress) + { + drive.fPacket.fPacketContent = fork_data_input; + drive.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drive.fPacket.fPacketLba = startFork; + + drive.fInput(drive.fPacket); + + kout << hex_number(fork_data_input->DataSize) << kendl; + kout << hex_number(size_of_data) << kendl; + kout << hex_number(fork_data_input->Flags) << kendl; + kout << fork_name << kendl; + kout << fork_data_input->ForkName << kendl; + kout << fork_data_input->CatalogName << kendl; + kout << catalog_name << kendl; + + if ((fork_data_input->Flags & kNeFSFlagCreated) && + KStringBuilder::Equals(fork_data_input->ForkName, fork_name) && + KStringBuilder::Equals(fork_data_input->CatalogName, catalog_name) && + fork_data_input->DataSize == size_of_data) + { + // ===================================================== // + // Store the blob now. + // ===================================================== // + + drive.fPacket.fPacketContent = buf; + drive.fPacket.fPacketSize = size_of_data; + drive.fPacket.fPacketLba = fork_data_input->DataOffset; + + kout << "data offset: " << hex_number(fork_data_input->DataOffset) << kendl; + + drive.fOutput(drive.fPacket); + + kout << "wrote data at offset: " << hex_number(fork_data_input->DataOffset) << kendl; + + delete fork_data_input; + delete[] buf; + + return true; + } + + // stumble upon a fork, store it. + + prev_fork = *fork_data_input; + + startFork = fork_data_input->NextSibling; + } + + delete[] buf; + delete fork_data_input; + + return false; +} + +/// @brief +/// @param catalog_name the catalog name. +/// @return the newly found catalog. +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::FindCatalog(_Input const Char* catalog_name, + Lba& out_lba, + Bool search_hidden, + Bool local_search) +{ + if (!catalog_name || + *catalog_name == 0) + return nullptr; + + NEFS_ROOT_PARTITION_BLOCK part{0}; + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + drive.fPacket.fPacketContent = ∂ + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + auto start_catalog_lba = kNeFSCatalogStartAddress; + const auto kStartCatalogList = start_catalog_lba; + + if (!KStringBuilder::Equals(catalog_name, NeFileSystemHelper::Root()) && local_search) + { + Char parent_name[kNeFSCatalogNameLen] = {0}; + + for (SizeT indexFill = 0; indexFill < rt_string_len(catalog_name); ++indexFill) + { + parent_name[indexFill] = catalog_name[indexFill]; + } + + SizeT indexReverseCopy = rt_string_len(parent_name); + + // zero character. + parent_name[--indexReverseCopy] = 0; + + // mandatory '/' character. + parent_name[--indexReverseCopy] = 0; + + while (parent_name[indexReverseCopy] != NeFileSystemHelper::Separator()) + { + parent_name[indexReverseCopy] = 0; + --indexReverseCopy; + } + + NEFS_CATALOG_STRUCT* parent_catalog = this->FindCatalog(parent_name, out_lba); + + if (parent_catalog && + !KStringBuilder::Equals(parent_name, NeFileSystemHelper::Root())) + { + start_catalog_lba = parent_catalog->NextSibling; + + delete parent_catalog; + parent_catalog = nullptr; + + local_search = YES; + } + else if (parent_catalog) + { + start_catalog_lba = parent_catalog->NextSibling; + + local_search = YES; + + delete parent_catalog; + parent_catalog = nullptr; + } + else if (!parent_catalog) + { + return nullptr; + } + } + + NEFS_CATALOG_STRUCT temporary_catalog{}; + + SizeT i = rt_string_len(catalog_name); + + // get rid of \0 + --i; + + if (catalog_name[i] == '/') + --i; + + while (catalog_name[i] != '/') + --i; + + const Char* tmp_name = (catalog_name + i); + +kNeFSSearchThroughCatalogList: + while (drive.fPacket.fPacketGood) + { + drive.fPacket.fPacketLba = start_catalog_lba; + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + + drive.fInput(drive.fPacket); + + if (KStringBuilder::Equals(tmp_name, temporary_catalog.Name)) + { + if (temporary_catalog.Status == kNeFSStatusLocked && + !search_hidden) + { + err_global_get() = kErrorFileLocked; + + goto NeFSContinueSearch; + } + + /// ignore unallocated catalog, break + if (!(temporary_catalog.Flags & kNeFSFlagCreated)) + { + err_global_get() = kErrorFileNotFound; + + goto NeFSContinueSearch; + } + + kout << "Found available catalog at: " << hex_number(start_catalog_lba) << kendl; + kout << "Found available catalog at: " << temporary_catalog.Name << kendl; + + NEFS_CATALOG_STRUCT* catalog_ptr = new NEFS_CATALOG_STRUCT(); + rt_copy_memory(&temporary_catalog, catalog_ptr, sizeof(NEFS_CATALOG_STRUCT)); + + out_lba = start_catalog_lba; + return catalog_ptr; + } + + NeFSContinueSearch: + start_catalog_lba = temporary_catalog.NextSibling; + + if (start_catalog_lba < part.StartCatalog) + break; + } + + if (local_search) + { + local_search = false; + start_catalog_lba = part.StartCatalog; + + goto kNeFSSearchThroughCatalogList; + } + + err_global_get() = kErrorFileNotFound; + + out_lba = 0UL; + + return nullptr; +} + +/// @brief Get catalog from filesystem. +/// @param name the catalog's name/ +/// @return +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::GetCatalog(_Input const Char* name) +{ + Lba unused = 0; + return this->FindCatalog(name, unused, YES); +} + +/// @brief Closes a catalog, (frees it). +/// @param catalog the catalog to close. +/// @return +_Output Boolean NeFileSystemParser::CloseCatalog(_Input _Output NEFS_CATALOG_STRUCT* catalog) +{ + if (!catalog) + return false; + + delete catalog; + catalog = nullptr; + + return true; +} + +/// @brief Mark catalog as removed. +/// @param catalog The catalog structure. +/// @return if the catalog was removed or not. +_Output Boolean NeFileSystemParser::RemoveCatalog(_Input const Char* catalog_name) +{ + if (!catalog_name || + KStringBuilder::Equals(catalog_name, NeFileSystemHelper::Root())) + { + err_global_get() = kErrorInternal; + return false; + } + + Lba out_lba = 0; + auto catalog = this->FindCatalog(catalog_name, out_lba); + + if (out_lba >= kNeFSCatalogStartAddress || + catalog->Flags & kNeFSFlagCreated) + { + catalog->Flags &= (~kNeFSFlagCreated); + catalog->Flags |= kNeFSFlagDeleted; + + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + drive.fPacket.fPacketLba = out_lba; // the catalog position. + drive.fPacket.fPacketSize = + sizeof(NEFS_CATALOG_STRUCT); // size of catalog. roughly the sector size. + drive.fPacket.fPacketContent = catalog; // the catalog itself. + + drive.fOutput(drive.fPacket); // send packet. + + Char partitionBlockBuf[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + drive.fPacket.fPacketContent = partitionBlockBuf; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + + drive.fInput(drive.fPacket); + + NEFS_ROOT_PARTITION_BLOCK* part_block = + reinterpret_cast<NEFS_ROOT_PARTITION_BLOCK*>(partitionBlockBuf); + + --part_block->CatalogCount; + ++part_block->FreeSectors; + + drive.fOutput(drive.fPacket); + + return true; + } + + delete catalog; + catalog = nullptr; + + return false; +} + +/// ***************************************************************** /// +/// Reading,Seek,Tell are unimplemented on catalogs, refer to forks I/O instead. +/// ***************************************************************** /// + +/***********************************************************************************/ +/// @brief Read the catalog data fork. +/// @param catalog +/// @param dataSz +/// @return +/***********************************************************************************/ + +VoidPtr NeFileSystemParser::ReadCatalog(_Input _Output NEFS_CATALOG_STRUCT* catalog, + _Input Bool is_rsrc_fork, + _Input SizeT dataSz, + _Input const Char* forkName) +{ + if (!catalog) + { + err_global_get() = kErrorInvalidData; + return nullptr; + } + + Lba dataForkLba = (!is_rsrc_fork) ? catalog->DataFork : catalog->ResourceFork; + Size dataForkSize = (!is_rsrc_fork) ? catalog->DataForkSize : catalog->ResourceForkSize; + + kout << "catalog " << catalog->Name + << ", fork: " << hex_number(dataForkLba) << kendl; + + NEFS_FORK_STRUCT* fs_buf = new NEFS_FORK_STRUCT(); + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + NEFS_FORK_STRUCT* fs_fork_data = nullptr; + + while (dataForkLba > kNeFSCatalogStartAddress) + { + drive.fPacket.fPacketLba = dataForkLba; + drive.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drive.fPacket.fPacketContent = fs_buf; + + drive.fInput(drive.fPacket); + + fs_fork_data = fs_buf; + + kout << "ForkName: " << fs_fork_data->ForkName << kendl; + kout << "CatalogName: " << fs_fork_data->CatalogName << kendl; + + if (KStringBuilder::Equals(forkName, fs_fork_data->ForkName) && + KStringBuilder::Equals(catalog->Name, fs_fork_data->CatalogName)) + break; + + dataForkLba = fs_fork_data->NextSibling; + } + + if (dataForkLba < kNeFSCatalogStartAddress) + { + delete fs_buf; + return nullptr; + } + + return fs_fork_data; +} + +/***********************************************************************************/ +/// @brief Seek in the data fork. +/// @param catalog the catalog offset. +/// @param off where to seek. +/// @return if the seeking was successful. +/***********************************************************************************/ + +bool NeFileSystemParser::Seek(_Input _Output NEFS_CATALOG_STRUCT* catalog, SizeT off) +{ + err_global_get() = kErrorUnimplemented; + return false; +} + +/***********************************************************************************/ +/// @brief Tell where we are inside the data fork. +/// @param catalog +/// @return The position on the file. +/***********************************************************************************/ + +SizeT NeFileSystemParser::Tell(_Input _Output NEFS_CATALOG_STRUCT* catalog) +{ + err_global_get() = kErrorUnimplemented; + return 0; +} + +namespace NeOS::NeFS +{ + /***********************************************************************************/ + /// @brief Construct NeFS drives. + /***********************************************************************************/ + Boolean fs_init_nefs(Void) noexcept + { + kout << "Creating main disk...\r"; + + kMountpoint.A() = io_construct_main_drive(); + + if (kMountpoint.A().fPacket.fPacketReadOnly == YES) + ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main filesystem cannot be mounted."); + + return YES; + } +} // namespace NeOS::NeFS + +#endif // ifdef __FSKIT_INCLUDES_NEFS__ diff --git a/dev/kernel/src/FileMgr.cc b/dev/kernel/src/FileMgr.cc new file mode 100644 index 00000000..b803253d --- /dev/null +++ b/dev/kernel/src/FileMgr.cc @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/FileMgr.h> +#include <NewKit/Utils.h> + +/// @file FileMgr.cc +//! @brief File System Manager API. + +namespace NeOS +{ + STATIC IFilesystemMgr* kMountedFilesystem = nullptr; + + /// @brief FilesystemMgr getter. + /// @return The mounted filesystem. + _Output IFilesystemMgr* IFilesystemMgr::GetMounted() + { + return kMountedFilesystem; + } + + /// @brief Unmount filesystem. + /// @return The unmounted filesystem. + _Output IFilesystemMgr* IFilesystemMgr::Unmount() + { + if (kMountedFilesystem) + { + auto mount = kMountedFilesystem; + kMountedFilesystem = nullptr; + + return mount; + } + + return nullptr; + } + + /// @brief Mount filesystem. + /// @param mount_ptr The filesystem to mount. + /// @return if it succeeded true, otherwise false. + _Output Bool IFilesystemMgr::Mount(_Input IFilesystemMgr* mount_ptr) + { + if (mount_ptr != nullptr) + { + kMountedFilesystem = mount_ptr; + return Yes; + } + + return No; + } +} // namespace NeOS diff --git a/dev/kernel/src/GUIDWizard.cc b/dev/kernel/src/GUIDWizard.cc new file mode 100644 index 00000000..96e15d85 --- /dev/null +++ b/dev/kernel/src/GUIDWizard.cc @@ -0,0 +1,72 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: GUIDWizard.cc + Purpose: GUID helper code + + Revision History: + +------------------------------------------- */ + +#include <CFKit/GUIDWizard.h> +#include <NewKit/Ref.h> + +// begin of ascii 'readable' characters. (A, C, C, 1, 2) +#define kUUIDAsciiBegin 47 +// @brief Size of UUID. +#define kUUIDSize 37 + +namespace CFKit::XRN::Version1 +{ + auto cf_make_sequence(const ArrayList<UInt32>& uuidSeq) -> Ref<GUIDSequence*> + { + GUIDSequence* seq = new GUIDSequence(); + MUST_PASS(seq); + + Ref<GUIDSequence*> seq_ref{seq}; + + seq_ref.Leak()->fMs1 = uuidSeq[0]; + seq_ref.Leak()->fMs2 = uuidSeq[1]; + seq_ref.Leak()->fMs3 = uuidSeq[2]; + seq_ref.Leak()->fMs4[0] = uuidSeq[3]; + seq_ref.Leak()->fMs4[1] = uuidSeq[4]; + seq_ref.Leak()->fMs4[2] = uuidSeq[5]; + seq_ref.Leak()->fMs4[3] = uuidSeq[6]; + seq_ref.Leak()->fMs4[4] = uuidSeq[7]; + seq_ref.Leak()->fMs4[5] = uuidSeq[8]; + seq_ref.Leak()->fMs4[6] = uuidSeq[9]; + seq_ref.Leak()->fMs4[7] = uuidSeq[10]; + + return seq_ref; + } + + // @brief Tries to make a guid out of a string. + // This function is not complete for now + auto cf_try_guid_to_string(Ref<GUIDSequence*>& seq) -> ErrorOr<Ref<KString>> + { + Char buf[kUUIDSize]; + + for (SizeT index = 0; index < 16; ++index) + { + buf[index] = seq.Leak()->u8[index] + kUUIDAsciiBegin; + } + + for (SizeT index = 16; index < 24; ++index) + { + buf[index] = seq.Leak()->u16[index] + kUUIDAsciiBegin; + } + + for (SizeT index = 24; index < 28; ++index) + { + buf[index] = seq.Leak()->u32[index] + kUUIDAsciiBegin; + } + + auto view = KStringBuilder::Construct(buf); + + if (view) + return ErrorOr<Ref<KString>>{view.Leak()}; + + return ErrorOr<Ref<KString>>{-1}; + } +} // namespace CFKit::XRN::Version1 diff --git a/dev/kernel/src/GUIDWrapper.cc b/dev/kernel/src/GUIDWrapper.cc new file mode 100644 index 00000000..cd4a6aa3 --- /dev/null +++ b/dev/kernel/src/GUIDWrapper.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <CFKit/GUIDWrapper.h> + +namespace CFKit::XRN +{ +} diff --git a/dev/kernel/src/HardwareThreadScheduler.cc b/dev/kernel/src/HardwareThreadScheduler.cc new file mode 100644 index 00000000..70502d40 --- /dev/null +++ b/dev/kernel/src/HardwareThreadScheduler.cc @@ -0,0 +1,225 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/HardwareThreadScheduler.h> +#include <CFKit/Property.h> + +/***********************************************************************************/ +///! @file HardwareThreadScheduler.cc +///! @brief This file handles multi processing in the Kernel. +///! @brief Multi processing is needed for multi-tasking operations. +/***********************************************************************************/ + +namespace NeOS +{ + /***********************************************************************************/ + /// @note Those symbols are needed in order to switch and validate the stack. + /***********************************************************************************/ + + EXTERN_C Bool hal_check_stack(HAL::StackFramePtr frame); + EXTERN_C Bool mp_register_process(HAL::StackFramePtr frame, ProcessID pid); + + STATIC HardwareThreadScheduler kHardwareThreadScheduler; + + ///! A HardwareThread class takes care of it's owned hardware thread. + ///! It has a stack for it's core. + + /***********************************************************************************/ + ///! @brief C++ constructor. + /***********************************************************************************/ + HardwareThread::HardwareThread() = default; + + /***********************************************************************************/ + ///! @brief C++ destructor. + /***********************************************************************************/ + HardwareThread::~HardwareThread() = default; + + /***********************************************************************************/ + //! @brief returns the id of the thread. + /***********************************************************************************/ + const ThreadID& HardwareThread::ID() noexcept + { + return fID; + } + + /***********************************************************************************/ + //! @brief returns the kind of thread we have. + /***********************************************************************************/ + const ThreadKind& HardwareThread::Kind() noexcept + { + return fKind; + } + + /***********************************************************************************/ + //! @brief is the thread busy? + //! @return whether the thread is busy or not. + /***********************************************************************************/ + Bool HardwareThread::IsBusy() noexcept + { + STATIC Int64 busy_timer = 0U; + constexpr Int64 kTimeoutMax = 0x1000000; // an arbitrary value used to tell if the timeout hasn't been reached yet. + + if (fBusy && (busy_timer > kTimeoutMax)) + { + busy_timer = 0U; + fBusy = No; + + return No; + } + + ++busy_timer; + + return fBusy; + } + + /***********************************************************************************/ + /// @brief Get processor stack frame. + /***********************************************************************************/ + + HAL::StackFramePtr HardwareThread::StackFrame() noexcept + { + MUST_PASS(this->fStack); + return this->fStack; + } + + Void HardwareThread::Busy(const Bool busy) noexcept + { + this->fBusy = busy; + } + + HardwareThread::operator bool() + { + return this->fStack && !this->fBusy; + } + + /***********************************************************************************/ + /// @brief Wakeup the processor. + /***********************************************************************************/ + + Void HardwareThread::Wake(const bool wakeup) noexcept + { + this->fWakeup = wakeup; + } + + /***********************************************************************************/ + /// @brief Switch to hardware thread. + /// @param stack the new hardware thread. + /// @retval true stack was changed, code is running. + /// @retval false stack is invalid, previous code is running. + /***********************************************************************************/ + Bool HardwareThread::Switch(VoidPtr image_ptr, Ptr8 stack_ptr, HAL::StackFramePtr frame, const ThreadID& pid) + { + if (this->IsBusy()) + return NO; + + this->fStack = frame; + this->fPID = pid; + + this->fStack->BP = reinterpret_cast<UIntPtr>(image_ptr); + this->fStack->SP = reinterpret_cast<UIntPtr>(stack_ptr); + + Bool ret = mp_register_process(fStack, this->fPID); + + if (ret) + this->Busy(YES); + + return ret; + } + + /***********************************************************************************/ + ///! @brief Tells if processor is waked up. + /***********************************************************************************/ + bool HardwareThread::IsWakeup() noexcept + { + return this->fWakeup; + } + + /***********************************************************************************/ + ///! @brief Constructor and destructors. + ///! @brief Default constructor. + /***********************************************************************************/ + + HardwareThreadScheduler::HardwareThreadScheduler() = default; + + /***********************************************************************************/ + ///! @brief Default destructor. + /***********************************************************************************/ + HardwareThreadScheduler::~HardwareThreadScheduler() = default; + + /***********************************************************************************/ + /// @brief Shared singleton function + /***********************************************************************************/ + HardwareThreadScheduler& HardwareThreadScheduler::The() + { + return kHardwareThreadScheduler; + } + + /***********************************************************************************/ + /// @brief Get Stack Frame of AP. + /***********************************************************************************/ + HAL::StackFramePtr HardwareThreadScheduler::Leak() noexcept + { + return fThreadList[fCurrentThread].fStack; + } + + /***********************************************************************************/ + /** + * Get Hardware thread at index. + * @param idx the index + * @return the reference to the hardware thread. + */ + /***********************************************************************************/ + Ref<HardwareThread*> HardwareThreadScheduler::operator[](const SizeT& idx) + { + if (idx == 0) + { + if (fThreadList[idx].Kind() != kAPSystemReserved) + { + fThreadList[idx].fKind = kAPBoot; + } + } + else if (idx >= kMaxAPInsideSched) + { + static HardwareThread* kFakeThread = nullptr; + return {kFakeThread}; + } + + return &fThreadList[idx]; + } + + /***********************************************************************************/ + /** + * Check if thread pool isn't empty. + * @return + */ + /***********************************************************************************/ + HardwareThreadScheduler::operator bool() noexcept + { + return !fThreadList.Empty(); + } + + /***********************************************************************************/ + /** + * Reverse operator bool + * @return + */ + /***********************************************************************************/ + bool HardwareThreadScheduler::operator!() noexcept + { + return fThreadList.Empty(); + } + + /***********************************************************************************/ + /// @brief Returns the amount of core present. + /// @return the number of APs. + /***********************************************************************************/ + SizeT HardwareThreadScheduler::Capacity() noexcept + { + return fThreadList.Count(); + } +} // namespace NeOS diff --git a/dev/kernel/src/IDylibObject.cc b/dev/kernel/src/IDylibObject.cc new file mode 100644 index 00000000..30a76af9 --- /dev/null +++ b/dev/kernel/src/IDylibObject.cc @@ -0,0 +1,15 @@ +/* + * ======================================================== + * + * neoskrnl + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#include <KernelKit/IDylibObject.h> +#include <KernelKit/DebugOutput.h> + +#include <KernelKit/UserProcessScheduler.h> + +using namespace NeOS; diff --git a/dev/kernel/src/IPEFDylibObject.cc b/dev/kernel/src/IPEFDylibObject.cc new file mode 100644 index 00000000..e994ad29 --- /dev/null +++ b/dev/kernel/src/IPEFDylibObject.cc @@ -0,0 +1,111 @@ +/* + * ======================================================== + * + * neoskrnl + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/PEF.h> +#include <KernelKit/IPEFDylibObject.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/ThreadLocalStorage.h> +#include <NewKit/Defines.h> + +/* ------------------------------------------- + + Revision History: + + 01/02/24: Reworked dll ABI, expect a rtl_init_dylib and + rtl_fini_dylib (amlel) + + 15/02/24: Breaking changes, changed the name of the + routines. (amlel) + + 07/28/24: Replace rt_library_free with rtl_fini_dylib + + 10/8/24: FIX: Fix log comment. + + ------------------------------------------- */ + +using namespace NeOS; + +/***********************************************************************************/ +/// @file IPEFDylibObject.cc +/// @brief PEF's Dylib runtime. +/***********************************************************************************/ + +/***********************************************************************************/ +/** @brief Library initializer. */ +/***********************************************************************************/ + +EXTERN_C IDylibRef rtl_init_dylib(UserProcess& process) +{ + IDylibRef dll_obj = tls_new_class<IPEFDylibObject>(); + + if (!dll_obj) + { + process.Crash(); + return nullptr; + } + + dll_obj->Mount(new IPEFDylibObject::DLL_TRAITS()); + + if (!dll_obj->Get()) + { + tls_delete_class(dll_obj); + dll_obj = nullptr; + + process.Crash(); + + return nullptr; + } + + dll_obj->Get()->ImageObject = + process.Image.fBlob; + + if (!dll_obj->Get()->ImageObject) + { + delete dll_obj->Get(); + + tls_delete_class(dll_obj); + dll_obj = nullptr; + + process.Crash(); + + return nullptr; + } + + dll_obj->Get()->ImageEntrypointOffset = + dll_obj->Load<VoidPtr>(kPefStart, rt_string_len(kPefStart, 0), kPefCode); + + return dll_obj; +} + +/***********************************************************************************/ +/** @brief Frees the dll_obj. */ +/** @note Please check if the dll_obj got freed! */ +/** @param dll_obj The dll_obj to free. */ +/** @param successful Reports if successful or not. */ +/***********************************************************************************/ + +EXTERN_C Void rtl_fini_dylib(UserProcess& process, IDylibRef dll_obj, BOOL* successful) +{ + MUST_PASS(successful); + + // sanity check (will also trigger a bug check if this fails) + if (dll_obj == nullptr) + { + *successful = false; + process.Crash(); + } + + delete dll_obj->Get(); + delete dll_obj; + + dll_obj = nullptr; + + *successful = true; +} diff --git a/dev/kernel/src/IndexableProperty.cc b/dev/kernel/src/IndexableProperty.cc new file mode 100644 index 00000000..404cddc3 --- /dev/null +++ b/dev/kernel/src/IndexableProperty.cc @@ -0,0 +1,57 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <CompilerKit/CompilerKit.h> +#include <FSKit/IndexableProperty.h> +#include <NewKit/MutableArray.h> +#include <NewKit/Utils.h> + +/// @brief File indexer API for fast path access. +/// BUGS: 0 + +#define kMaxLenIndexer (256U) + +namespace NeOS +{ + namespace Indexer + { + IndexProperty& IndexableProperty::Leak() noexcept + { + return fIndex; + } + + Void IndexableProperty::AddFlag(Int16 flag) + { + fFlags |= flag; + } + + Void IndexableProperty::RemoveFlag(Int16 flag) + { + fFlags &= flag; + } + + Int16 IndexableProperty::HasFlag(Int16 flag) + { + return fFlags & flag; + } + + /// @brief Index a file into the indexer instance. + /// @param filename filesystem path to access. + /// @param filenameLen used bytes in path. + /// @param indexer the filesystem indexer. + /// @return none, check before if indexer can be claimed (using indexer.HasFlag(kIndexerClaimed)). + Void fs_index_file(const Char* filename, SizeT filenameLen, IndexableProperty& indexer) + { + if (!indexer.HasFlag(kIndexerClaimed)) + { + indexer.AddFlag(kIndexerClaimed); + rt_copy_memory((VoidPtr)indexer.Leak().Path, (VoidPtr)filename, filenameLen); + + kout << "FSKit: Indexed new file: " << filename << kendl; + } + } + } // namespace Indexer +} // namespace NeOS diff --git a/dev/kernel/src/Json.cc b/dev/kernel/src/Json.cc new file mode 100644 index 00000000..48567b5f --- /dev/null +++ b/dev/kernel/src/Json.cc @@ -0,0 +1,10 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Json.h> + +/// @brief Undefined object, is null in length. +RTL_INIT_OBJECT(NeOS::Json::kNull, NeOS::Json); diff --git a/dev/kernel/src/KString.cc b/dev/kernel/src/KString.cc new file mode 100644 index 00000000..d96ef38c --- /dev/null +++ b/dev/kernel/src/KString.cc @@ -0,0 +1,218 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/KString.h> +#include <NewKit/Utils.h> + +/// @file KString.cc +/// @brief Kernel String manipulation file. + +namespace NeOS +{ + Char* KString::Data() + { + return this->fData; + } + + const Char* KString::CData() const + { + return const_cast<const Char*>(this->fData); + } + + Size KString::Length() const + { + return this->fDataSz; + } + + bool KString::operator==(const KString& rhs) const + { + if (rhs.Length() != this->Length()) + return false; + + for (Size index = 0; index < this->Length(); ++index) + { + if (rhs.fData[index] != this->fData[index]) + return false; + } + + return true; + } + + bool KString::operator==(const Char* rhs) const + { + if (rt_string_len(rhs) != this->Length()) + return false; + + for (Size index = 0; index < rt_string_len(rhs); ++index) + { + if (rhs[index] != this->fData[index]) + return false; + } + + return true; + } + + bool KString::operator!=(const KString& rhs) const + { + if (rhs.Length() != this->Length()) + return false; + + for (Size index = 0; index < rhs.Length(); ++index) + { + if (rhs.fData[index] == this->fData[index]) + return false; + } + + return true; + } + + bool KString::operator!=(const Char* rhs) const + { + if (rt_string_len(rhs) != this->Length()) + return false; + + for (Size index = 0; index < rt_string_len(rhs); ++index) + { + if (rhs[index] == this->fData[index]) + return false; + } + + return true; + } + + ErrorOr<KString> KStringBuilder::Construct(const Char* data) + { + if (!data || *data == 0) + return {}; + + KString* view = new KString(rt_string_len(data)); + (*view) += data; + + return ErrorOr<KString>(*view); + } + + const Char* KStringBuilder::FromBool(const Char* fmt, bool i) + { + if (!fmt) + return ("?"); + + const Char* boolean_expr = i ? "YES" : "NO"; + Char* ret = (Char*)RTL_ALLOCA((sizeof(char) * i) ? 4 : 5 + rt_string_len(fmt)); + + if (!ret) + return ("?"); + + const auto fmt_len = rt_string_len(fmt); + const auto res_len = rt_string_len(boolean_expr); + + for (Size idx = 0; idx < fmt_len; ++idx) + { + if (fmt[idx] == '%') + { + SizeT result_cnt = idx; + + for (auto y_idx = idx; y_idx < res_len; ++y_idx) + { + ret[result_cnt] = boolean_expr[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; + } + + bool KStringBuilder::Equals(const Char* lhs, const Char* rhs) + { + if (rt_string_len(rhs) != rt_string_len(lhs)) + return false; + + for (Size index = 0; index < rt_string_len(rhs); ++index) + { + if (rhs[index] != lhs[index]) + return false; + } + + return true; + } + + bool KStringBuilder::Equals(const WideChar* lhs, const WideChar* rhs) + { + for (Size index = 0; rhs[index] != 0; ++index) + { + if (rhs[index] != lhs[index]) + return false; + } + + return true; + } + + const Char* KStringBuilder::Format(const Char* fmt, const Char* fmt2) + { + if (!fmt || !fmt2) + return ("?"); + + Char* ret = + (Char*)RTL_ALLOCA(sizeof(char) * (rt_string_len(fmt2) + rt_string_len(fmt))); + + if (!ret) + return ("?"); + + const auto len = rt_string_len(fmt); + + for (Size idx = 0; idx < len; ++idx) + { + if (fmt[idx] == '%' && idx < rt_string_len(fmt) && fmt[idx] == 's') + { + Size result_cnt = idx; + + for (Size y_idx = 0; y_idx < rt_string_len(fmt2); ++y_idx) + { + ret[result_cnt] = fmt2[y_idx]; + ++result_cnt; + } + } + + ret[idx] = fmt[idx]; + } + + return ret; + } + + STATIC void rt_string_append(Char* lhs, const Char* rhs, Int32 cur) + { + SizeT sz_rhs = rt_string_len(rhs); + SizeT rhs_i = 0; + + for (; rhs_i < sz_rhs; ++rhs_i) + { + lhs[rhs_i + cur] = rhs[rhs_i]; + } + } + + KString& KString::operator+=(const Char* rhs) + { + rt_string_append(this->fData, rhs, this->fCur); + this->fCur += rt_string_len(rhs); + + return *this; + } + + KString& KString::operator+=(const KString& rhs) + { + if (rt_string_len(rhs.fData) > this->Length()) + return *this; + + rt_string_append(this->fData, const_cast<Char*>(rhs.fData), this->fCur); + this->fCur += rt_string_len(const_cast<Char*>(rhs.fData)); + + return *this; + } +} // namespace NeOS diff --git a/dev/kernel/src/LPC.cc b/dev/kernel/src/LPC.cc new file mode 100644 index 00000000..b6b2e11b --- /dev/null +++ b/dev/kernel/src/LPC.cc @@ -0,0 +1,34 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/LPC.h> +#include <NewKit/KernelPanic.h> + +namespace NeOS +{ + STATIC Bool kRaiseOnBugCheck = false; + + /// @brief Does a system wide bug check. + /// @param void no params. + /// @return if error-free: false, otherwise true. + Boolean err_bug_check(void) noexcept + { + if (kRaiseOnBugCheck) + { + ke_panic(RUNTIME_CHECK_BAD_BEHAVIOR); + } + + return No; + } + + /// @brief Tells if we should raise a bug check not. + /// @param void + /// @return void + Void err_bug_check_raise(Void) noexcept + { + kRaiseOnBugCheck = true; + } +} // namespace NeOS diff --git a/dev/kernel/src/LockDelegate.cc b/dev/kernel/src/LockDelegate.cc new file mode 100644 index 00000000..df62c6f3 --- /dev/null +++ b/dev/kernel/src/LockDelegate.cc @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/LockDelegate.h> + +namespace NeOS +{ + /// @note Leave it empty for now. +} // namespace NeOS diff --git a/dev/kernel/src/MemoryMgr.cc b/dev/kernel/src/MemoryMgr.cc new file mode 100644 index 00000000..4e13ea15 --- /dev/null +++ b/dev/kernel/src/MemoryMgr.cc @@ -0,0 +1,289 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/LPC.h> +#include <KernelKit/MemoryMgr.h> +#include <NewKit/Crc32.h> +#include <NewKit/PageMgr.h> +#include <NewKit/Utils.h> +#include <ArchKit/ArchKit.h> + +/* ------------------------------------------- + + Revision History: + 10/8/24: FIX: Fix useless long name, alongside a new WR (WriteRead) field. + 20/10/24: Fix mm_new_ and mm_delete_ APIs inside MemoryMgr.h header. (amlal) + 27/01/25: Reworked code as the memory manager. + + ------------------------------------------- */ + +//! @file MemoryMgr.cc +//! @brief Heap algorithm that serves as the main memory manager. + +#define kKernelHeapMagic (0xD4D75) +#define kKernelHeapAlignSz (__BIGGEST_ALIGNMENT__) + +namespace NeOS +{ + /// @brief Contains data structures and algorithms for the heap. + namespace Detail + { + struct PACKED HEAP_INFORMATION_BLOCK; + + /// @brief Kernel heap information block. + /// Located before the address bytes. + /// | HIB | CLASS/STRUCT/DATA TYPES... | + struct PACKED HEAP_INFORMATION_BLOCK final + { + ///! @brief 32-bit value which contains the magic number of the heap. + UInt32 fMagic : 24; + + ///! @brief Is the heap present? + UInt8 fPresent : 1; + + /// @brief Is this value writable? + UInt8 fWriteRead : 1; + + /// @brief Is this value owned by the user? + UInt8 fUser : 1; + + /// @brief Is this a page pointer? + UInt8 fPage : 1; + + /// @brief 32-bit CRC checksum. + UInt32 fCRC32; + + /// @brief 64-bit Allocation flags. + UInt16 fFlags; + + /// @brief 64-bit pointer size. + SizeT fSize; + + /// @brief 64-bit target offset pointer. + UIntPtr fOffset; + + /// @brief Padding bytes for header. + UInt8 fPadding[kKernelHeapAlignSz]; + }; + + /// @brief Check for heap address validity. + /// @param heap_ptr The address_ptr to check. + /// @return Bool if the pointer is valid or not. + _Output auto mm_check_heap_address(VoidPtr heap_ptr) -> Bool + { + if (!heap_ptr) + return false; + + auto base_heap = ((IntPtr)heap_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK); + + /// Add that check in case we're having an integer underflow. /// + + if (base_heap < 0) + { + return false; + } + + return true; + } + + typedef HEAP_INFORMATION_BLOCK* HEAP_INFORMATION_BLOCK_PTR; + } // namespace Detail + + /// @brief Declare a new size for ptr_heap. + /// @param ptr_heap the pointer. + /// @return Newly allocated heap header. + _Output auto mm_realloc_heap(VoidPtr ptr_heap, SizeT new_sz) -> VoidPtr + { + if (Detail::mm_check_heap_address(ptr_heap) == No) + return nullptr; + + if (!ptr_heap || new_sz < 1) + return nullptr; + + kout << "This function is not implemented by NeOSKrnl, please use the BSD's realloc instead.\r"; + ke_panic(RUNTIME_CHECK_INVALID); + + return nullptr; + } + + /// @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. + _Output VoidPtr mm_new_heap(const SizeT sz, const bool wr, const bool user) + { + auto sz_fix = sz; + + if (sz_fix == 0) + return nullptr; + + sz_fix += sizeof(Detail::HEAP_INFORMATION_BLOCK); + + PageMgr heap_mgr; + auto wrapper = heap_mgr.Request(wr, user, No, sz_fix); + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + wrapper.VirtualAddress() + sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + heap_info_ptr->fSize = sz_fix; + heap_info_ptr->fMagic = kKernelHeapMagic; + heap_info_ptr->fCRC32 = 0; // dont fill it for now. + heap_info_ptr->fOffset = reinterpret_cast<UIntPtr>(heap_info_ptr) + sizeof(Detail::HEAP_INFORMATION_BLOCK); + heap_info_ptr->fPage = No; + heap_info_ptr->fWriteRead = wr; + heap_info_ptr->fUser = user; + heap_info_ptr->fPresent = Yes; + + rt_set_memory(heap_info_ptr->fPadding, 0, kKernelHeapAlignSz); + + auto result = reinterpret_cast<VoidPtr>(heap_info_ptr->fOffset); + + kout << "Registered heap address: " << hex_number(reinterpret_cast<UIntPtr>(heap_info_ptr)) << kendl; + + return result; + } + + /// @brief Makes a page heap. + /// @param heap_ptr the pointer to make a page heap. + /// @return kErrorSuccess if successful, otherwise an error code. + _Output Int32 mm_make_page(VoidPtr heap_ptr) + { + if (Detail::mm_check_heap_address(heap_ptr) == No) + return kErrorHeapNotPresent; + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (!heap_info_ptr) + return kErrorHeapNotPresent; + + heap_info_ptr->fPage = true; + + kout << "Registered page address: " << hex_number(reinterpret_cast<UIntPtr>(heap_info_ptr)) << kendl; + + return kErrorSuccess; + } + + /// @brief Overwrites and set the flags of a heap header. + /// @param heap_ptr the pointer to update. + /// @param flags the flags to set. + _Output Int32 mm_make_flags(VoidPtr heap_ptr, UInt64 flags) + { + if (Detail::mm_check_heap_address(heap_ptr) == No) + return kErrorHeapNotPresent; + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (!heap_info_ptr) + return kErrorHeapNotPresent; + + heap_info_ptr->fFlags = flags; + + return kErrorSuccess; + } + + /// @brief Gets the flags of a heap header. + /// @param heap_ptr the pointer to get. + _Output UInt64 mm_get_flags(VoidPtr heap_ptr) + { + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (!heap_info_ptr) + return kErrorHeapNotPresent; + + return heap_info_ptr->fFlags; + } + + /// @brief Declare pointer as free. + /// @param heap_ptr the pointer. + /// @return + _Output Int32 mm_delete_heap(VoidPtr heap_ptr) + { + if (Detail::mm_check_heap_address(heap_ptr) == No) + return kErrorHeapNotPresent; + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)(heap_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (heap_info_ptr && heap_info_ptr->fMagic == kKernelHeapMagic) + { + if (!heap_info_ptr->fPresent) + { + return kErrorHeapNotPresent; + } + + heap_info_ptr->fSize = 0UL; + heap_info_ptr->fPresent = No; + heap_info_ptr->fOffset = 0; + heap_info_ptr->fCRC32 = 0; + heap_info_ptr->fWriteRead = No; + heap_info_ptr->fUser = No; + heap_info_ptr->fMagic = 0; + + PTEWrapper page_wrapper(No, No, No, reinterpret_cast<UIntPtr>(heap_info_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + Ref<PTEWrapper> pte_address{page_wrapper}; + + PageMgr heap_mgr; + heap_mgr.Free(pte_address); + + kout << "Address has been successfully freed." << kendl; + + return kErrorSuccess; + } + + return kErrorInternal; + } + + /// @brief Check if pointer is a valid Kernel pointer. + /// @param heap_ptr the pointer + /// @return if it exists. + _Output Boolean mm_is_valid_heap(VoidPtr heap_ptr) + { + if (heap_ptr && HAL::mm_is_bitmap(heap_ptr)) + { + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)(heap_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + return (heap_info_ptr && heap_info_ptr->fPresent && heap_info_ptr->fMagic == kKernelHeapMagic); + } + + return No; + } + + /// @brief Protect the heap with a CRC value. + /// @param heap_ptr HIB pointer. + /// @return if it valid: point has crc now., otherwise fail. + _Output Boolean mm_protect_heap(VoidPtr heap_ptr) + { + if (heap_ptr) + { + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + /// if valid, present and is heap header, then compute crc32 + if (heap_info_ptr && heap_info_ptr->fPresent && kKernelHeapMagic == heap_info_ptr->fMagic) + { + heap_info_ptr->fCRC32 = + ke_calculate_crc32((Char*)heap_info_ptr->fOffset, heap_info_ptr->fSize); + + return Yes; + } + } + + return No; + } +} // namespace NeOS diff --git a/dev/kernel/src/MutableArray.cc b/dev/kernel/src/MutableArray.cc new file mode 100644 index 00000000..8464a283 --- /dev/null +++ b/dev/kernel/src/MutableArray.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/MutableArray.h> diff --git a/dev/kernel/src/Network/IPAddr.cc b/dev/kernel/src/Network/IPAddr.cc new file mode 100644 index 00000000..6f523086 --- /dev/null +++ b/dev/kernel/src/Network/IPAddr.cc @@ -0,0 +1,129 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/IP.h> +#include <NewKit/Utils.h> + +namespace NeOS +{ + Char* RawIPAddress::Address() + { + return fAddr; + } + + RawIPAddress::RawIPAddress(char bytes[4]) + { + rt_copy_memory(bytes, fAddr, 4); + } + + BOOL RawIPAddress::operator==(const RawIPAddress& ipv4) + { + for (Size index = 0; index < 4; ++index) + { + if (ipv4.fAddr[index] != fAddr[index]) + return false; + } + + return true; + } + + BOOL RawIPAddress::operator!=(const RawIPAddress& ipv4) + { + for (Size index = 0; index < 4; ++index) + { + if (ipv4.fAddr[index] == fAddr[index]) + return false; + } + + return true; + } + + Char& RawIPAddress::operator[](const Size& index) + { + kout << "[RawIPAddress::operator[]] Fetching Index...\r"; + + static char IP_PLACEHOLDER = '0'; + if (index > 4) + return IP_PLACEHOLDER; + + return fAddr[index]; + } + + RawIPAddress6::RawIPAddress6(char bytes[8]) + { + rt_copy_memory(bytes, fAddr, 8); + } + + char& RawIPAddress6::operator[](const Size& index) + { + kout << "[RawIPAddress6::operator[]] Fetching Index...\r"; + + static char IP_PLACEHOLDER = '0'; + if (index > 8) + return IP_PLACEHOLDER; + + return fAddr[index]; + } + + bool RawIPAddress6::operator==(const RawIPAddress6& ipv6) + { + for (SizeT index = 0; index < 8; ++index) + { + if (ipv6.fAddr[index] != fAddr[index]) + return false; + } + + return true; + } + + bool RawIPAddress6::operator!=(const RawIPAddress6& ipv6) + { + for (SizeT index = 0; index < 8; ++index) + { + if (ipv6.fAddr[index] == fAddr[index]) + return false; + } + + return true; + } + + ErrorOr<KString> IPFactory::ToKString(Ref<RawIPAddress6>& ipv6) + { + auto str = KStringBuilder::Construct(ipv6.Leak().Address()); + return str; + } + + ErrorOr<KString> IPFactory::ToKString(Ref<RawIPAddress>& ipv4) + { + auto str = KStringBuilder::Construct(ipv4.Leak().Address()); + return str; + } + + bool IPFactory::IpCheckVersion4(const Char* ip) + { + if (!ip) + return NO; + + Int32 cnter = 0; + + for (SizeT base = 0; base < rt_string_len(ip); ++base) + { + if (ip[base] == '.') + { + cnter = 0; + } + else + { + if (cnter == 3) + return false; + + ++cnter; + } + } + + return true; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/IPCAddr.cc b/dev/kernel/src/Network/IPCAddr.cc new file mode 100644 index 00000000..75a54a36 --- /dev/null +++ b/dev/kernel/src/Network/IPCAddr.cc @@ -0,0 +1,32 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + ------------------------------------------- */ + +#include <NetworkKit/IPC.h> +#include <KernelKit/LPC.h> +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + bool IPC_ADDR::operator==(const IPC_ADDR& addr) noexcept + { + return addr.UserProcessID == this->UserProcessID && addr.UserProcessTeam == this->UserProcessTeam; + } + + bool IPC_ADDR::operator==(IPC_ADDR& addr) noexcept + { + return addr.UserProcessID == this->UserProcessID && addr.UserProcessTeam == this->UserProcessTeam; + } + + bool IPC_ADDR::operator!=(const IPC_ADDR& addr) noexcept + { + return addr.UserProcessID != this->UserProcessID || addr.UserProcessTeam != this->UserProcessTeam; + } + + bool IPC_ADDR::operator!=(IPC_ADDR& addr) noexcept + { + return addr.UserProcessID != this->UserProcessID || addr.UserProcessTeam != this->UserProcessTeam; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/IPCMsg.cc b/dev/kernel/src/Network/IPCMsg.cc new file mode 100644 index 00000000..f5bec6f7 --- /dev/null +++ b/dev/kernel/src/Network/IPCMsg.cc @@ -0,0 +1,125 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/IPC.h> +#include <KernelKit/LPC.h> +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + /// @internal internal use for IPC system only. + /// @brief The internal sanitize function. + Bool ipc_int_sanitize_packet(IPC_MSG* pckt) + { + auto endian = RTL_ENDIAN(pckt, ((Char*)pckt)[0]); + + switch (endian) + { + case Endian::kEndianBig: { + if (pckt->IpcEndianess == kIPCLittleEndian) + goto ipc_check_failed; + + break; + } + case Endian::kEndianLittle: { + if (pckt->IpcEndianess == kIPCBigEndian) + goto ipc_check_failed; + + break; + } + case Endian::kEndianMixed: { + if (pckt->IpcEndianess == kIPCMixedEndian) + goto ipc_check_failed; + + break; + } + default: + goto ipc_check_failed; + } + + if (pckt->IpcFrom == pckt->IpcTo || + pckt->IpcPacketSize > kIPCMsgSize) + { + goto ipc_check_failed; + } + + return pckt->IpcPacketSize > 1 && pckt->IpcHeaderMagic == kIPCHeaderMagic; + + ipc_check_failed: + err_local_get() = kErrorIPC; + return false; + } + + /// @brief Sanitize packet function + /// @retval true packet is correct. + /// @retval false packet is incorrect and process has crashed. + Bool ipc_sanitize_packet(IPC_MSG* pckt) + { + if (!pckt || + !ipc_int_sanitize_packet(pckt)) + { + return false; + } + + return true; + } + + /// @brief Construct packet function + /// @retval true packet is correct. + /// @retval false packet is incorrect and process has crashed. + Bool ipc_construct_packet(_Output IPC_MSG** pckt_in) + { + // don't act if it's not even valid. + if (!pckt_in) + return false; + + if (!*pckt_in) + *pckt_in = new IPC_MSG(); + + MUST_PASS(*pckt_in); + + if (*pckt_in) + { + const auto endianess = RTL_ENDIAN((*pckt_in), ((Char*)(*pckt_in))[0]); + + (*pckt_in)->IpcHeaderMagic = kIPCHeaderMagic; + + (*pckt_in)->IpcEndianess = static_cast<UInt8>(endianess); + (*pckt_in)->IpcPacketSize = sizeof(IPC_MSG); + + (*pckt_in)->IpcTo.UserProcessID = 0; + (*pckt_in)->IpcTo.UserProcessTeam = 0; + + (*pckt_in)->IpcFrom.UserProcessID = 0; + (*pckt_in)->IpcFrom.UserProcessTeam = 0; + + return Yes; + } + + return No; + } + + /// @brief Pass message from **src** to **target** + /// @param src Source message. + /// @param target Target message. + Bool IPC_MSG::Pass(IPC_MSG* src, IPC_MSG* target) noexcept + { + if (src && target && (target != src)) + { + if (src->IpcMsgSz > target->IpcMsgSz) + return No; + + if (target->IpcMsgSz > src->IpcMsgSz) + return No; + + rt_copy_memory(src->IpcData, target->IpcData, src->IpcMsgSz); + + return Yes; + } + + return No; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/MACAddressGetter.cc b/dev/kernel/src/Network/MACAddressGetter.cc new file mode 100644 index 00000000..627bcd34 --- /dev/null +++ b/dev/kernel/src/Network/MACAddressGetter.cc @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/MAC.h> + +namespace NeOS +{ + Array<WideChar, kMACAddrLen>& MacAddressGetter::AsBytes() + { + return this->fMacAddress; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/NetworkDevice.cc b/dev/kernel/src/Network/NetworkDevice.cc new file mode 100644 index 00000000..f2971265 --- /dev/null +++ b/dev/kernel/src/Network/NetworkDevice.cc @@ -0,0 +1,35 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/NetworkDevice.h> +#include <NewKit/Utils.h> + +namespace NeOS +{ + /// \brief Getter for fNetworkName. + const Char* NetworkDevice::Name() const + { + return this->fNetworkName; + } + + /// \brief Setter for fNetworkName. + Boolean NetworkDevice::Name(const Char* devnam) + { + if (devnam == nullptr) + return NO; + + if (*devnam == 0) + return NO; + + if (rt_string_len(devnam) > cNetworkNameLen) + return NO; + + rt_copy_memory((VoidPtr)devnam, + (VoidPtr)this->fNetworkName, rt_string_len(devnam)); + + return YES; + } +} // namespace NeOS diff --git a/dev/kernel/src/New+Delete.cc b/dev/kernel/src/New+Delete.cc new file mode 100644 index 00000000..1e0a3421 --- /dev/null +++ b/dev/kernel/src/New+Delete.cc @@ -0,0 +1,50 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/MemoryMgr.h> +#include <NewKit/New.h> + +void* operator new[](size_t sz) +{ + if (sz == 0) + ++sz; + + return NeOS::mm_new_heap(sz, true, false); +} + +void* operator new(size_t sz) +{ + if (sz == 0) + ++sz; + + return NeOS::mm_new_heap(sz, true, false); +} + +void operator delete[](void* ptr) +{ + if (ptr == nullptr) + return; + + NeOS::mm_delete_heap(ptr); +} + +void operator delete(void* ptr) +{ + if (ptr == nullptr) + return; + + NeOS::mm_delete_heap(ptr); +} + +void operator delete(void* ptr, size_t sz) +{ + if (ptr == nullptr) + return; + + NE_UNUSED(sz); + + NeOS::mm_delete_heap(ptr); +} diff --git a/dev/kernel/src/OwnPtr.cc b/dev/kernel/src/OwnPtr.cc new file mode 100644 index 00000000..e4d529aa --- /dev/null +++ b/dev/kernel/src/OwnPtr.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/OwnPtr.h> diff --git a/dev/kernel/src/PEFCodeMgr.cc b/dev/kernel/src/PEFCodeMgr.cc new file mode 100644 index 00000000..426a1e26 --- /dev/null +++ b/dev/kernel/src/PEFCodeMgr.cc @@ -0,0 +1,268 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/MemoryMgr.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/UserProcessScheduler.h> +#include <NewKit/Defines.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/OwnPtr.h> +#include <NewKit/KString.h> + +/// @brief PEF stack size symbol. +#define kPefStackSizeSymbol "__PEFSizeOfReserveStack" +#define kPefHeapSizeSymbol "__PEFSizeOfReserveHeap" +#define kPefNameSymbol "__PEFProgramName" + +namespace NeOS +{ + namespace Detail + { + /***********************************************************************************/ + /// @brief Get the PEF platform signature according to the compiled architecture. + /***********************************************************************************/ + UInt32 ldr_get_platform(void) noexcept + { +#if defined(__NE_32X0__) + return kPefArch32x0; +#elif defined(__NE_64X0__) + return kPefArch64x0; +#elif defined(__NE_AMD64__) + return kPefArchAMD64; +#elif defined(__NE_PPC64__) + return kPefArchPowerPC; +#elif defined(__NE_ARM64__) + return kPefArchARM64; +#else + return kPefArchInvalid; +#endif // __32x0__ || __64x0__ || __x86_64__ + } + } // namespace Detail + + /***********************************************************************************/ + /// @brief PEF loader constructor w/ blob. + /// @param blob file blob. + /***********************************************************************************/ + PEFLoader::PEFLoader(const VoidPtr blob) + : fCachedBlob(blob) + { + MUST_PASS(fCachedBlob); + fBad = false; + } + + /***********************************************************************************/ + /// @brief PEF loader constructor. + /// @param path the filesystem path. + /***********************************************************************************/ + PEFLoader::PEFLoader(const Char* path) + : fCachedBlob(nullptr), fBad(false), fFatBinary(false) + { + fFile.New(const_cast<Char*>(path), kRestrictRB); + fPath = KStringBuilder::Construct(path).Leak(); + + auto kPefHeader = "PEF_CONTAINER"; + + fCachedBlob = fFile->Read(kPefHeader, mib_cast(16)); + + PEFContainer* container = reinterpret_cast<PEFContainer*>(fCachedBlob); + + if (container->Cpu == Detail::ldr_get_platform() && + container->Magic[0] == kPefMagic[0] && + container->Magic[1] == kPefMagic[1] && + container->Magic[2] == kPefMagic[2] && + container->Magic[3] == kPefMagic[3] && + container->Magic[4] == kPefMagic[4] && container->Abi == kPefAbi) + { + return; + } + else if (container->Magic[4] == kPefMagic[0] && + container->Magic[3] == kPefMagic[1] && + container->Magic[2] == kPefMagic[2] && + container->Magic[1] == kPefMagic[3] && + container->Magic[0] == kPefMagic[4] && container->Abi == kPefAbi) + { + /// This is a fat binary. + this->fFatBinary = true; + return; + } + + fBad = true; + + if (fCachedBlob) + mm_delete_heap(fCachedBlob); + + kout << "PEFLoader: warn: Executable format error!\r"; + + fCachedBlob = nullptr; + } + + /***********************************************************************************/ + /// @brief PEF destructor. + /***********************************************************************************/ + PEFLoader::~PEFLoader() + { + if (fCachedBlob) + mm_delete_heap(fCachedBlob); + + fFile.Delete(); + } + + /***********************************************************************************/ + /// @brief Finds the symbol according to it's name. + /// @param name name of symbol. + /// @param kind kind of symbol we want. + /***********************************************************************************/ + VoidPtr PEFLoader::FindSymbol(const Char* name, Int32 kind) + { + if (!fCachedBlob || fBad || !name) + return nullptr; + + PEFContainer* container = reinterpret_cast<PEFContainer*>(fCachedBlob); + + auto blob = fFile->Read(name, mib_cast(16)); + + PEFCommandHeader* container_header = reinterpret_cast<PEFCommandHeader*>(blob); + + constexpr auto cMangleCharacter = '$'; + const Char* cContainerKinds[] = {".code64", ".data64", ".zero64", nullptr}; + + ErrorOr<KString> error_or_symbol; + + switch (kind) + { + case kPefCode: { + error_or_symbol = KStringBuilder::Construct(cContainerKinds[0]); // code symbol. + break; + } + case kPefData: { + error_or_symbol = KStringBuilder::Construct(cContainerKinds[1]); // data symbol. + break; + } + case kPefZero: { + error_or_symbol = KStringBuilder::Construct(cContainerKinds[2]); // block starting symbol. + break; + } + default: + return nullptr; // prevent that from the kernel's mode perspective, let that happen if it were + // a user process. + } + + Char* unconst_symbol = const_cast<Char*>(name); + + for (SizeT i = 0UL; i < rt_string_len(unconst_symbol, kPefNameLen); ++i) + { + if (unconst_symbol[i] == ' ') + { + unconst_symbol[i] = cMangleCharacter; + } + } + + error_or_symbol.Leak().Leak() += name; + + for (SizeT index = 0; index < container->Count; ++index) + { + if (KStringBuilder::Equals(container_header->Name, + error_or_symbol.Leak().Leak().CData())) + { + if (container_header->Kind == kind) + { + if (container_header->Cpu != Detail::ldr_get_platform()) + { + if (!this->fFatBinary) + { + mm_delete_heap(blob); + return nullptr; + } + } + + Char* container_blob_value = new Char[container_header->Size]; + + rt_copy_memory((VoidPtr)((Char*)blob + sizeof(PEFCommandHeader)), container_blob_value, container_header->Size); + mm_delete_heap(blob); + + kout << "PEFLoader: INFO: Load stub: " << container_header->Name << "!\r"; + + return container_blob_value; + } + } + } + + mm_delete_heap(blob); + return nullptr; + } + + /// @brief Finds the executable entrypoint. + /// @return + ErrorOr<VoidPtr> PEFLoader::FindStart() + { + if (auto sym = this->FindSymbol(kPefStart, kPefCode); sym) + return ErrorOr<VoidPtr>(sym); + + return ErrorOr<VoidPtr>(kErrorExecutable); + } + + /// @brief Tells if the executable is loaded or not. + /// @return + bool PEFLoader::IsLoaded() noexcept + { + return !fBad && fCachedBlob; + } + + const Char* PEFLoader::Path() + { + return fPath.Leak().CData(); + } + + const Char* PEFLoader::AsString() + { +#ifdef __32x0__ + return "32x0 PEF executable."; +#elif defined(__64x0__) + return "64x0 PEF executable."; +#elif defined(__x86_64__) + return "x86_64 PEF executable."; +#elif defined(__aarch64__) + return "AARCH64 PEF executable."; +#elif defined(__powerpc64__) + return "POWER64 PEF executable."; +#else + return "???? PEF executable."; +#endif // __32x0__ || __64x0__ || __x86_64__ || __powerpc64__ + } + + const Char* PEFLoader::MIME() + { + return kPefApplicationMime; + } + + ErrorOr<VoidPtr> PEFLoader::GetBlob() + { + return ErrorOr<VoidPtr>{this->fCachedBlob}; + } + + namespace Utils + { + ProcessID rtl_create_process(PEFLoader& exec, const Int32& process_kind) noexcept + { + auto errOrStart = exec.FindStart(); + + if (errOrStart.Error() != kErrorSuccess) + return kProcessInvalidID; + + auto id = UserProcessScheduler::The().Spawn(reinterpret_cast<const Char*>(exec.FindSymbol(kPefNameSymbol, kPefData)), errOrStart.Leak().Leak(), exec.GetBlob().Leak().Leak()); + + if (id != kProcessInvalidID) + { + UserProcessScheduler::The().CurrentTeam().AsArray()[id].Kind = process_kind; + UserProcessScheduler::The().CurrentTeam().AsArray()[id].StackSize = *(UIntPtr*)exec.FindSymbol(kPefStackSizeSymbol, kPefData); + UserProcessScheduler::The().CurrentTeam().AsArray()[id].MemoryLimit = *(UIntPtr*)exec.FindSymbol(kPefHeapSizeSymbol, kPefData); + } + + return id; + } + } // namespace Utils +} // namespace NeOS diff --git a/dev/kernel/src/PRDT.cc b/dev/kernel/src/PRDT.cc new file mode 100644 index 00000000..9ea3e70b --- /dev/null +++ b/dev/kernel/src/PRDT.cc @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/KString.h> +#include <StorageKit/PRDT.h> + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief constructs a new PRD. + /// @param prd PRD reference. + /// @note This doesnt construct a valid, please fill it by yourself. + /***********************************************************************************/ + void construct_prdt(Ref<PRDT>& prd) + { + prd.Leak().fPhysAddress = 0x0; + prd.Leak().fSectorCount = 0x0; + prd.Leak().fEndBit = 0x0; + } +} // namespace NeOS diff --git a/dev/kernel/src/PageMgr.cc b/dev/kernel/src/PageMgr.cc new file mode 100644 index 00000000..eb7c7e03 --- /dev/null +++ b/dev/kernel/src/PageMgr.cc @@ -0,0 +1,110 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/PageMgr.h> + +#ifdef __NE_AMD64__ +#include <HALKit/AMD64/Paging.h> +#elif defined(__NE_ARM64__) +#include <HALKit/ARM64/Paging.h> +#endif // ifdef __NE_AMD64__ || defined(__NE_ARM64__) + +namespace NeOS +{ + PTEWrapper::PTEWrapper(Boolean Rw, Boolean User, Boolean ExecDisable, UIntPtr VirtAddr) + : fRw(Rw), + fUser(User), + fExecDisable(ExecDisable), + fVirtAddr(VirtAddr), + fCache(false), + fShareable(false), + fWt(false), + fPresent(true), + fAccessed(false) + { + } + + PTEWrapper::~PTEWrapper() = default; + + /// @brief Flush virtual address. + /// @param VirtAddr + Void PageMgr::FlushTLB() + { +#ifndef __NE_MINIMAL_OS__ + hal_flush_tlb(); +#endif // !__NE_MINIMAL_OS__ + } + + /// @brief Reclaim freed page. + /// @return + Bool PTEWrapper::Reclaim() + { + if (!this->fPresent) + { + this->fPresent = true; + return true; + } + + return false; + } + + /// @brief Request a PTE. + /// @param Rw r/w? + /// @param User user mode? + /// @param ExecDisable disable execution on page? + /// @return + PTEWrapper PageMgr::Request(Boolean Rw, Boolean User, Boolean ExecDisable, SizeT Sz) + { + // Store PTE wrapper right after PTE. + VoidPtr ptr = NeOS::HAL::mm_alloc_bitmap(Rw, User, Sz, false); + + return PTEWrapper{Rw, User, ExecDisable, reinterpret_cast<UIntPtr>(ptr)}; + } + + /// @brief Disable BitMap. + /// @param wrapper the wrapper. + /// @return If the page bitmap was cleared or not. + Bool PageMgr::Free(Ref<PTEWrapper>& wrapper) + { + if (!NeOS::HAL::mm_free_bitmap((VoidPtr)wrapper.Leak().VirtualAddress())) + return false; + + return true; + } + + /// @brief Virtual PTE address. + /// @return The virtual address of the page. + const UIntPtr PTEWrapper::VirtualAddress() + { + return (fVirtAddr); + } + + Bool PTEWrapper::Shareable() + { + return fShareable; + } + + Bool PTEWrapper::Present() + { + return fPresent; + } + + Bool PTEWrapper::Access() + { + return fAccessed; + } + + Void PTEWrapper::NoExecute(const bool enable) + { + fExecDisable = enable; + } + + Bool PTEWrapper::NoExecute() + { + return fExecDisable; + } +} // namespace NeOS diff --git a/dev/kernel/src/Pmm.cc b/dev/kernel/src/Pmm.cc new file mode 100644 index 00000000..b3d5e79e --- /dev/null +++ b/dev/kernel/src/Pmm.cc @@ -0,0 +1,98 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/Pmm.h> + +#if defined(__NE_ARM64__) +#include <HALKit/ARM64/Processor.h> +#endif // defined(__NE_ARM64__) + +#if defined(__NE_AMD64__) +#include <HALKit/AMD64/Processor.h> +#endif // defined(__NE_AMD64__) + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Pmm constructor. + /***********************************************************************************/ + Pmm::Pmm() + : fPageMgr() + { + kout << "[PMM] Allocate PageMemoryMgr"; + } + + Pmm::~Pmm() = default; + + /***********************************************************************************/ + /// @param If this returns Null pointer, enter emergency mode. + /// @param user is this a user page? + /// @param readWrite is it r/w? + /***********************************************************************************/ + Ref<PTEWrapper> Pmm::RequestPage(Boolean user, Boolean readWrite) + { + PTEWrapper pt = fPageMgr.Leak().Request(user, readWrite, false, kPageSize); + + if (pt.fPresent) + { + kout << "[PMM]: Allocation failed.\r"; + return {}; + } + + return Ref<PTEWrapper>(pt); + } + + Boolean Pmm::FreePage(Ref<PTEWrapper> PageRef) + { + if (!PageRef) + return false; + + PageRef.Leak().fPresent = false; + + return true; + } + + Boolean Pmm::TogglePresent(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fPresent = Enable; + + return true; + } + + Boolean Pmm::ToggleUser(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fRw = Enable; + + return true; + } + + Boolean Pmm::ToggleRw(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fRw = Enable; + + return true; + } + + Boolean Pmm::ToggleShare(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fShareable = Enable; + + return true; + } +} // namespace NeOS diff --git a/dev/kernel/src/Property.cc b/dev/kernel/src/Property.cc new file mode 100644 index 00000000..8f3b5314 --- /dev/null +++ b/dev/kernel/src/Property.cc @@ -0,0 +1,45 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <CFKit/Property.h> + +namespace CFKit +{ + /***********************************************************************************/ + /// @brief Destructor. + /***********************************************************************************/ + Property::~Property() = default; + + /***********************************************************************************/ + /// @brief Constructor. + /***********************************************************************************/ + Property::Property() = default; + + /***********************************************************************************/ + /// @brief Check if property's name equals to name. + /// @param name string to check. + /***********************************************************************************/ + Bool Property::StringEquals(KString& name) + { + return this->fName && this->fName == name; + } + + /***********************************************************************************/ + /// @brief Gets the key (name) of property. + /***********************************************************************************/ + KString& Property::GetKey() + { + return this->fName; + } + + /***********************************************************************************/ + /// @brief Gets the value of the property. + /***********************************************************************************/ + PropertyId& Property::GetValue() + { + return fValue; + } +} // namespace CFKit diff --git a/dev/kernel/src/Ref.cc b/dev/kernel/src/Ref.cc new file mode 100644 index 00000000..6fadb033 --- /dev/null +++ b/dev/kernel/src/Ref.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Ref.h> diff --git a/dev/kernel/src/SoftwareTimer.cc b/dev/kernel/src/SoftwareTimer.cc new file mode 100644 index 00000000..5e4214e9 --- /dev/null +++ b/dev/kernel/src/SoftwareTimer.cc @@ -0,0 +1,39 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/Timer.h> + +/// @brief SoftwareTimer class, meant to be generic. + +using namespace NeOS; + +SoftwareTimer::SoftwareTimer(Int64 seconds) + : fWaitFor(seconds) +{ + fDigitalTimer = new IntPtr(); + MUST_PASS(fDigitalTimer); +} + +SoftwareTimer::~SoftwareTimer() +{ + delete fDigitalTimer; + fDigitalTimer = nullptr; + + fWaitFor = 0; +} + +BOOL SoftwareTimer::Wait() noexcept +{ + if (fWaitFor < 1) + return NO; + + while (*fDigitalTimer < (*fDigitalTimer + fWaitFor)) + { + ++(*fDigitalTimer); + } + + return YES; +} diff --git a/dev/kernel/src/Storage/AHCIDeviceInterface.cc b/dev/kernel/src/Storage/AHCIDeviceInterface.cc new file mode 100644 index 00000000..8d987ab5 --- /dev/null +++ b/dev/kernel/src/Storage/AHCIDeviceInterface.cc @@ -0,0 +1,36 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/AHCI.h> + +using namespace NeOS; + +/// @brief Class constructor +/// @param Out Drive output +/// @param In Drive input +/// @param Cleanup Drive cleanup. +AHCIDeviceInterface::AHCIDeviceInterface(void (*out)(IDeviceObject* self, MountpointInterface* outpacket), + void (*in)(IDeviceObject* self, MountpointInterface* inpacket), + void (*cleanup)(void)) + : IDeviceObject(out, in), fCleanup(cleanup) +{ +} + +/// @brief Class desctructor +AHCIDeviceInterface::~AHCIDeviceInterface() +{ + MUST_PASS(fCleanup); + + if (fCleanup) + fCleanup(); +} + +/// @brief Returns the name of the device interface. +/// @return it's name as a string. +const Char* AHCIDeviceInterface::Name() const +{ + return "/dev/sda{}"; +} diff --git a/dev/kernel/src/Storage/ATADeviceInterface.cc b/dev/kernel/src/Storage/ATADeviceInterface.cc new file mode 100644 index 00000000..9f1a0068 --- /dev/null +++ b/dev/kernel/src/Storage/ATADeviceInterface.cc @@ -0,0 +1,88 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/ATA.h> + +using namespace NeOS; + +/// @brief Class constructor +/// @param Out Drive output +/// @param In Drive input +/// @param Cleanup Drive cleanup. +ATADeviceInterface::ATADeviceInterface( + void (*Out)(IDeviceObject*, MountpointInterface* outpacket), + void (*In)(IDeviceObject*, MountpointInterface* inpacket), + void (*Cleanup)(void)) + : IDeviceObject(Out, In), fCleanup(Cleanup) +{ +} + +/// @brief Class desctructor +ATADeviceInterface::~ATADeviceInterface() +{ + MUST_PASS(fCleanup); + if (fCleanup) + fCleanup(); +} + +/// @brief Returns the name of the device interface. +/// @return it's name as a string. +const Char* ATADeviceInterface::Name() const +{ + return "/dev/hda{}"; +} + +/// @brief Output operator. +/// @param Data +/// @return +ATADeviceInterface& ATADeviceInterface::operator<<(MountpointInterface* Data) +{ + if (!Data) + return *this; + + for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) + { + auto interface = Data->GetAddressOf(driveCount); + if ((interface) && rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) == 0) + { + continue; + } + else if ((interface) && + rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) != 0) + { + return *this; + } + } + + return (ATADeviceInterface&)IDeviceObject<MountpointInterface*>::operator<<( + Data); +} + +/// @brief Input operator. +/// @param Data +/// @return +ATADeviceInterface& ATADeviceInterface::operator>>(MountpointInterface* Data) +{ + if (!Data) + return *this; + + for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) + { + auto interface = Data->GetAddressOf(driveCount); + if ((interface) && rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) == 0) + { + continue; + } + else if ((interface) && + rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) != 0) + { + return *this; + } + } + + return (ATADeviceInterface&)IDeviceObject<MountpointInterface*>::operator>>( + Data); +} diff --git a/dev/kernel/src/Storage/NVMEDeviceInterface.cc b/dev/kernel/src/Storage/NVMEDeviceInterface.cc new file mode 100644 index 00000000..3e2c2c53 --- /dev/null +++ b/dev/kernel/src/Storage/NVMEDeviceInterface.cc @@ -0,0 +1,28 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/NVME.h> + +namespace NeOS +{ + NVMEDeviceInterface::NVMEDeviceInterface(void (*out)(IDeviceObject*, MountpointInterface* outpacket), + void (*in)(IDeviceObject*, MountpointInterface* inpacket), + void (*cleanup)(void)) + : IDeviceObject(out, in), fCleanup(cleanup) + { + } + + NVMEDeviceInterface::~NVMEDeviceInterface() + { + if (fCleanup) + fCleanup(); + } + + const Char* NVMEDeviceInterface::Name() const + { + return ("/dev/nvme{}"); + } +} // namespace NeOS diff --git a/dev/kernel/src/Storage/SCSIDeviceInterface.cc b/dev/kernel/src/Storage/SCSIDeviceInterface.cc new file mode 100644 index 00000000..cc625cdb --- /dev/null +++ b/dev/kernel/src/Storage/SCSIDeviceInterface.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/SCSI.h> + +///! @brief ATAPI SCSI packet. +const scsi_packet_type<12> kCDRomPacketTemplate = {0x43, 0, 1, 0, 0, 0, + 0, 12, 0x40, 0, 0}; diff --git a/dev/kernel/src/Stream.cc b/dev/kernel/src/Stream.cc new file mode 100644 index 00000000..8d060556 --- /dev/null +++ b/dev/kernel/src/Stream.cc @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: Stream.cc + Purpose: Stream object + + Revision History: + +------------------------------------------- */ + +#include <NewKit/Stream.h> diff --git a/dev/kernel/src/System/SwapDisk.cc b/dev/kernel/src/System/SwapDisk.cc new file mode 100644 index 00000000..921ea86d --- /dev/null +++ b/dev/kernel/src/System/SwapDisk.cc @@ -0,0 +1,47 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss Labs, all rights reserved. + +------------------------------------------- */ + +#include <SystemKit/SwapDisk.h> +#include <KernelKit/FileMgr.h> + +namespace NeOS +{ + BOOL SwapDisk::Write(const Char* fork_name, const SizeT fork_name_len, SWAP_DISK_HEADER* data, const SizeT data_len) + { + if (!fork_name || !fork_name_len) + return NO; + + if (data_len > kSwapBlockMaxSize) + return NO; + + if (!data) + return NO; + + FileStream file(kSwapPageFile, "wb"); + + auto ret = file.Write(fork_name, data, sizeof(SWAP_DISK_HEADER) + data_len); + + if (ret.Error()) + return NO; + + return YES; + } + + SWAP_DISK_HEADER* SwapDisk::Read(const Char* fork_name, const SizeT fork_name_len, const SizeT data_len) + { + if (!fork_name || !fork_name_len) + return nullptr; + + if (data_len > kSwapBlockMaxSize) + return nullptr; + + FileStream file(kSwapPageFile, "rb"); + + VoidPtr blob = file.Read(fork_name, sizeof(SWAP_DISK_HEADER) + data_len); + + return (SWAP_DISK_HEADER*)blob; + } +} // namespace NeOS diff --git a/dev/kernel/src/ThreadLocalStorage.cc b/dev/kernel/src/ThreadLocalStorage.cc new file mode 100644 index 00000000..b25b4288 --- /dev/null +++ b/dev/kernel/src/ThreadLocalStorage.cc @@ -0,0 +1,67 @@ +/* + * ======================================================== + * + * neoskrnl + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#include <NewKit/KString.h> +#include <CFKit/Property.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/ThreadLocalStorage.h> + +/***********************************************************************************/ +/// @bugs: 0 +/// @file ThreadLocalStorage.cc +/// @brief Process Thread Local Storage. +/***********************************************************************************/ + +using namespace NeOS; + +/** + * @brief Checks for cookie inside the TIB. + * @param tib_ptr the TIB to check. + * @return if the cookie is enabled, true; false otherwise + */ + +Boolean tls_check_tib(THREAD_INFORMATION_BLOCK* tib_ptr) +{ + if (!tib_ptr || + !tib_ptr->Record) + return false; + + ICodec encoder; + const Char* tib_as_bytes = encoder.AsBytes(tib_ptr); + + kout << "TLS: Validating the TIB...\r"; + + return tib_as_bytes[kCookieMag0Idx] == kCookieMag0 && tib_as_bytes[kCookieMag1Idx] == kCookieMag1 && + tib_as_bytes[kCookieMag2Idx] == kCookieMag2; +} + +/** + * @brief System call implementation of the TLS check. + * @param tib_ptr The TIB record. + * @return if the TIB record is valid or not. + */ +EXTERN_C Bool tls_check_syscall_impl(NeOS::VoidPtr tib_ptr) noexcept +{ + if (!tib_ptr) + { + kout << "TLS: Failed because of an invalid TIB...\r"; + return No; + } + + THREAD_INFORMATION_BLOCK* tib = reinterpret_cast<THREAD_INFORMATION_BLOCK*>(tib_ptr); + + if (!tls_check_tib(tib)) + { + kout << "TLS: Failed because of an invalid TIB...\r"; + return No; + } + + kout << "TLS Pass.\r"; + return Yes; +} diff --git a/dev/kernel/src/Timer.cc b/dev/kernel/src/Timer.cc new file mode 100644 index 00000000..5df81134 --- /dev/null +++ b/dev/kernel/src/Timer.cc @@ -0,0 +1,19 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/Timer.h> + +///! BUGS: 0 +///! @file Timer.cc +///! @brief Software Timer implementation + +using namespace NeOS; + +/// @brief Unimplemented as it is an interface. +BOOL TimerInterface::Wait() noexcept +{ + return NO; +} diff --git a/dev/kernel/src/User.cc b/dev/kernel/src/User.cc new file mode 100644 index 00000000..3c23c59e --- /dev/null +++ b/dev/kernel/src/User.cc @@ -0,0 +1,195 @@ +/* + * ======================================================== + * + * NeKernel + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * File: User.cc + * Purpose: User class, used to provide authentication and security. + * + * ======================================================== + */ + +#include <KernelKit/User.h> +#include <KernelKit/LPC.h> +#include <NewKit/KernelPanic.h> +#include <KernelKit/FileMgr.h> +#include <KernelKit/MemoryMgr.h> + +#define kStdUserType (0xEE) +#define kSuperUserType (0xEF) + +/// @file User.cc +/// @brief Multi-user support. + +namespace NeOS +{ + namespace Detail + { + //////////////////////////////////////////////////////////// + /// \brief Constructs a password by hashing the password. + /// \param password password to hash. + /// \return the hashed password + //////////////////////////////////////////////////////////// + const Int32 cred_construct_token(Char* password, const Char* in_password, User* user, SizeT length) + { + if (!password || !user) + return 1; + + kout << "cred_construct_token: Hashing user password...\r"; + + for (SizeT i_pass = 0UL; i_pass < length; ++i_pass) + { + const Char cur_chr = in_password[i_pass]; + + if (cur_chr == 0) + break; + + password[i_pass] = cur_chr | (user->IsStdUser() ? kStdUserType : kSuperUserType); + } + + kout << "cred_construct_token: Hashed user password.\r"; + + return 0; + } + } // namespace Detail + + //////////////////////////////////////////////////////////// + /// @brief User ring constructor. + //////////////////////////////////////////////////////////// + User::User(const Int32& sel, const Char* user_name) + : mUserRing((UserRingKind)sel) + { + MUST_PASS(sel >= 0); + rt_copy_memory((VoidPtr)user_name, this->mUserName, rt_string_len(user_name)); + } + + //////////////////////////////////////////////////////////// + /// @brief User ring constructor. + //////////////////////////////////////////////////////////// + User::User(const UserRingKind& ring_kind, const Char* user_name) + : mUserRing(ring_kind) + { + rt_copy_memory((VoidPtr)user_name, this->mUserName, rt_string_len(user_name)); + } + + //////////////////////////////////////////////////////////// + /// @brief User destructor class. + //////////////////////////////////////////////////////////// + User::~User() = default; + + Bool User::Save(const UserPublicKey password_to_fill) noexcept + { + if (!password_to_fill || + *password_to_fill == 0) + return No; + + SizeT len = rt_string_len(password_to_fill); + + UserPublicKey password = new UserPublicKeyType[len]; + + MUST_PASS(password); + + rt_set_memory(password, 0, len); + + // fill data first, generate hash. + // return false on error. + + rt_copy_memory((VoidPtr)password_to_fill, password, len); + + if (!Detail::cred_construct_token(password, password_to_fill, this, len)) + { + delete[] password; + password = nullptr; + + return No; + } + + // then store password. + + rt_copy_memory(password, this->mUserKey, rt_string_len(password_to_fill)); + + delete[] password; + password = nullptr; + + kout << "User::Save: Saved password successfully...\r"; + + return Yes; + } + + Bool User::Matches(const UserPublicKey password_to_fill) noexcept + { + if (!password_to_fill || + *password_to_fill) + return No; + + SizeT len = rt_string_len(password_to_fill); + + Char* password = new Char[len]; + MUST_PASS(password); + + // fill data first, generate hash. + // return false on error. + + rt_copy_memory((VoidPtr)password_to_fill, password, len); + + if (!Detail::cred_construct_token(password, password_to_fill, this, len)) + { + delete[] password; + password = nullptr; + + return No; + } + + kout << "User::Matches: Validating hashed passwords...\r"; + + // now check if the password matches. + if (rt_string_cmp(password, this->mUserKey, rt_string_len(this->mUserKey)) == 0) + { + kout << "User::Matches: Password matches.\r"; + return Yes; + } + + kout << "User::Matches: Password doesn't match.\r"; + return No; + } + + Bool User::operator==(const User& lhs) + { + return lhs.mUserRing == this->mUserRing; + } + + Bool User::operator!=(const User& lhs) + { + return lhs.mUserRing != this->mUserRing; + } + + //////////////////////////////////////////////////////////// + /// @brief Returns the user's name. + //////////////////////////////////////////////////////////// + + Char* User::Name() noexcept + { + return this->mUserName; + } + + //////////////////////////////////////////////////////////// + /// @brief Returns the user's ring. + /// @return The king of ring the user is attached to. + //////////////////////////////////////////////////////////// + + const UserRingKind& User::Ring() noexcept + { + return this->mUserRing; + } + + Bool User::IsStdUser() noexcept + { + return this->Ring() == UserRingKind::kRingStdUser; + } + + Bool User::IsSuperUser() noexcept + { + return this->Ring() == UserRingKind::kRingSuperUser; + } +} // namespace NeOS diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc new file mode 100644 index 00000000..1087ac6b --- /dev/null +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -0,0 +1,621 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + FILE: UserProcessScheduler.cc + PURPOSE: Low level/Ring-3 Process scheduler. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file UserProcessScheduler.cc +/// @brief Low level/Ring-3 process scheduler. +/***********************************************************************************/ + +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/HardwareThreadScheduler.h> +#include <KernelKit/IPEFDylibObject.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/MemoryMgr.h> +#include <NewKit/KString.h> +#include <KernelKit/LPC.h> + +///! BUGS: 0 + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Exit Code global variable. + /***********************************************************************************/ + + STATIC UInt32 kLastExitCode = 0U; + + /***********************************************************************************/ + /// @brief External reference of the thread scheduler. + /***********************************************************************************/ + + STATIC UserProcessScheduler kProcessScheduler; + + UserProcess::UserProcess() = default; + UserProcess::~UserProcess() = default; + + /// @brief Gets the last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + + const UInt32& sched_get_exit_code(void) noexcept + { + return kLastExitCode; + } + + /***********************************************************************************/ + /// @brief Crashes the current process. + /***********************************************************************************/ + + Void UserProcess::Crash() + { + if (this->Status != ProcessStatusKind::kRunning) + return; + + kout << this->Name << ": crashed, error id: " << number(kErrorProcessFault) << kendl; + this->Exit(kErrorProcessFault); + } + + /***********************************************************************************/ + /// @brief boolean operator, check status. + /***********************************************************************************/ + + UserProcess::operator bool() + { + return this->Status == ProcessStatusKind::kRunning; + } + + /***********************************************************************************/ + /// @brief Gets the local last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + /***********************************************************************************/ + + const UInt32& UserProcess::GetExitCode() noexcept + { + return this->fLastExitCode; + } + + /***********************************************************************************/ + /// @brief Error code variable getter. + /***********************************************************************************/ + + Int32& UserProcess::GetLocalCode() noexcept + { + return this->fLocalCode; + } + + /***********************************************************************************/ + /// @brief Wakes process header. + /// @param should_wakeup if the program shall wakeup or not. + /***********************************************************************************/ + + Void UserProcess::Wake(const Bool should_wakeup) + { + this->Status = + should_wakeup ? ProcessStatusKind::kRunning : ProcessStatusKind::kFrozen; + } + + /***********************************************************************************/ + /** @brief Allocate pointer to track list. */ + /***********************************************************************************/ + + ErrorOr<VoidPtr> UserProcess::New(const SizeT& sz, const SizeT& pad_amount) + { +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + auto vm_register = hal_read_cr3(); + hal_write_cr3(this->VMRegister); + + auto ptr = mm_new_heap(sz + pad_amount, Yes, Yes); + + hal_write_cr3(vm_register); +#else + auto ptr = mm_new_heap(sz + pad_amount, Yes, Yes); +#endif + + if (!this->ProcessMemoryHeap) + { + this->ProcessMemoryHeap = new ProcessMemoryHeapList(); + + this->ProcessMemoryHeap->MemoryEntryPad = pad_amount; + this->ProcessMemoryHeap->MemoryEntrySize = sz; + + this->ProcessMemoryHeap->MemoryEntry = ptr; + + this->ProcessMemoryHeap->MemoryPrev = nullptr; + this->ProcessMemoryHeap->MemoryNext = nullptr; + } + else + { + ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; + ProcessMemoryHeapList* prev_entry = nullptr; + + while (entry) + { + if (entry->MemoryEntry == nullptr) + break; // chose to break here, when we get an already allocated memory entry for our needs. + + prev_entry = entry; + entry = entry->MemoryNext; + } + + entry->MemoryNext = new ProcessMemoryHeapList(); + entry->MemoryNext->MemoryEntry = ptr; + + entry->MemoryNext->MemoryPrev = entry; + entry->MemoryNext->MemoryNext = nullptr; + } + + this->UsedMemory += sz; + + return ErrorOr<VoidPtr>(ptr); + } + + /***********************************************************************************/ + /// @brief Gets the name of the current process. + /***********************************************************************************/ + + const Char* UserProcess::GetName() noexcept + { + return this->Name; + } + + /***********************************************************************************/ + /// @brief Gets the owner of the process. + /***********************************************************************************/ + + const User* UserProcess::GetOwner() noexcept + { + return this->Owner; + } + + /// @brief UserProcess status getter. + const ProcessStatusKind& UserProcess::GetStatus() noexcept + { + return this->Status; + } + + /***********************************************************************************/ + /** + @brief Affinity is the time slot allowed for the process. + */ + /***********************************************************************************/ + + const AffinityKind& UserProcess::GetAffinity() noexcept + { + return this->Affinity; + } + + /***********************************************************************************/ + /** + @brief Exit process method. + @param exit_code The process's exit code. + */ + /***********************************************************************************/ + + Void UserProcess::Exit(const Int32& exit_code) + { + this->Status = exit_code > 0 ? ProcessStatusKind::kKilled : ProcessStatusKind::kFrozen; + this->fLastExitCode = exit_code; + + kLastExitCode = exit_code; + + auto memory_heap_list = this->ProcessMemoryHeap; + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + auto pd = hal_read_cr3(); + hal_write_cr3(this->VMRegister); +#endif + + // Deleting memory lists. Make sure to free all of them. + while (memory_heap_list) + { + if (memory_heap_list->MemoryEntry) + { + MUST_PASS(mm_delete_heap(memory_heap_list->MemoryEntry)); + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + hal_write_cr3(pd); +#endif + + auto next = memory_heap_list->MemoryNext; + + mm_delete_heap(memory_heap_list); + + memory_heap_list = next; + } + + //! Free the memory's page directory. + HAL::mm_free_bitmap(this->VMRegister); + + //! Delete image if not done already. + if (this->Image.fCode && mm_is_valid_heap(this->Image.fCode)) + mm_delete_heap(this->Image.fCode); + + if (this->Image.fBlob && mm_is_valid_heap(this->Image.fBlob)) + mm_delete_heap(this->Image.fBlob); + + if (this->StackFrame && mm_is_valid_heap(this->StackFrame)) + mm_delete_heap((VoidPtr)this->StackFrame); + + this->Image.fBlob = nullptr; + this->Image.fCode = nullptr; + this->StackFrame = nullptr; + + if (this->Kind == kExectuableDylibKind) + { + Bool success = false; + + rtl_fini_dylib(*this, reinterpret_cast<IPEFDylibObject*>(this->DylibDelegate), &success); + + if (!success) + { + ke_panic(RUNTIME_CHECK_PROCESS); + } + + this->DylibDelegate = nullptr; + } + + if (this->StackReserve) + mm_delete_heap(reinterpret_cast<VoidPtr>(this->StackReserve)); + + this->ProcessId = 0; + this->Status = ProcessStatusKind::kFinished; + + --this->ProcessParentTeam->mProcessCount; + + delete this; + } + + /***********************************************************************************/ + /// @brief Add process to team. + /// @param process the process *Ref* class. + /// @return the process index inside the team. + /***********************************************************************************/ + + ProcessID UserProcessScheduler::Spawn(const Char* name, VoidPtr code, VoidPtr image) + { + ProcessID pid = this->mTeam.mProcessCount; + + if (pid > kSchedProcessLimitPerTeam) + { + return kErrorProcessFault; + } + + ++this->mTeam.mProcessCount; + + UserProcess& process = this->mTeam.mProcessList[pid]; + + process.Image.fCode = code; + process.Image.fBlob = image; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(name)), process.Name, rt_string_len(name)); + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + process.VMRegister = new PDE(); + + if (!process.VMRegister) + { + process.Crash(); + return kErrorProcessFault; + } + + UInt32 flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.VMRegister, process.VMRegister, flags); +#endif // __NE_VIRTUAL_MEMORY_SUPPORT__ + + process.StackFrame = new HAL::StackFrame(); + + if (!process.StackFrame) + { + process.Crash(); + return kErrorProcessFault; + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.StackFrame, process.StackFrame, flags); +#endif // __NE_VIRTUAL_MEMORY_SUPPORT__ + + // React according to process kind. + switch (process.Kind) + { + case UserProcess::kExectuableDylibKind: { + process.DylibDelegate = rtl_init_dylib(process); + MUST_PASS(process.DylibDelegate); + } + default: { + kout << "Unknown process kind: " << hex_number(process.Kind) << kendl; + break; + } + } + + process.StackReserve = new UInt8[process.StackSize]; + rt_set_memory(process.StackReserve, 0, process.StackSize); + + if (!process.StackReserve) + { + process.Crash(); + return kErrorProcessFault; + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.StackReserve, process.StackReserve, flags); +#endif // __NE_VIRTUAL_MEMORY_SUPPORT__ + + process.ProcessParentTeam = &mTeam; + + process.ProcessId = pid; + process.Status = ProcessStatusKind::kStarting; + process.PTime = (UIntPtr)AffinityKind::kStandard; + + kout << "PID: " << number(process.ProcessId) << kendl; + kout << "Name: " << process.Name << kendl; + + return pid; + } + + /***********************************************************************************/ + /// @brief Retrieves the singleton of the process scheduler. + /***********************************************************************************/ + + UserProcessScheduler& UserProcessScheduler::The() + { + return kProcessScheduler; + } + + /***********************************************************************************/ + + /// @brief Remove process from the team. + /// @param process_id process slot inside team. + /// @retval true process was removed. + /// @retval false process doesn't exist in team. + + /***********************************************************************************/ + + const Bool UserProcessScheduler::Remove(ProcessID process_id) + { + // check if process is within range. + if (process_id > mTeam.mProcessList.Count()) + return No; + + mTeam.mProcessList[process_id].Exit(0); + + return Yes; + } + + /// @brief Is it a user scheduler? + + const Bool UserProcessScheduler::IsUser() + { + return Yes; + } + + /// @brief Is it a kernel scheduler? + + const Bool UserProcessScheduler::IsKernel() + { + return No; + } + + /// @brief Is it a SMP scheduler? + + const Bool UserProcessScheduler::HasMP() + { + return Yes; + } + + /***********************************************************************************/ + /// @brief Run User scheduler object. + /// @return Process count executed within a team. + /***********************************************************************************/ + + const SizeT UserProcessScheduler::Run() noexcept + { + SizeT process_index = 0UL; //! we store this guy to tell the scheduler how many + //! things we have scheduled. + + if (mTeam.mProcessCount < 1) + { + kout << "UserProcessScheduler::Run(): This team doesn't have any process!\r"; + return 0UL; + } + for (; process_index < mTeam.AsArray().Capacity(); ++process_index) + { + auto& process = mTeam.AsArray()[process_index]; + + //! check if the process needs to be run. + if (UserProcessHelper::CanBeScheduled(process)) + { + // Set current process header. + this->CurrentProcess() = process; + + process.PTime = static_cast<Int32>(process.Affinity); + + kout << "Switch to: '" << process.Name << "'.\r"; + + // tell helper to find a core to schedule on. + BOOL ret = UserProcessHelper::Switch(process.Image.fCode, &process.StackReserve[process.StackSize - 1], process.StackFrame, + process.ProcessId); + + if (!ret) + { + if (process.Affinity == AffinityKind::kRealTime) + continue; + + kout << "The process: " << process.Name << ", is not valid! Crashing it...\r"; + + process.Crash(); + } + } + else + { + --process.PTime; + } + } + + return process_index; + } + + /// @brief Gets the current scheduled team. + /// @return + UserProcessTeam& UserProcessScheduler::CurrentTeam() + { + return mTeam; + } + + /// @internal + + /// @brief Gets current running process. + /// @return + Ref<UserProcess>& UserProcessScheduler::CurrentProcess() + { + return mTeam.AsRef(); + } + + /// @brief Current proccess id getter. + /// @return UserProcess ID integer. + ErrorOr<PID> UserProcessHelper::TheCurrentPID() + { + if (!kProcessScheduler.CurrentProcess()) + return ErrorOr<PID>{kErrorProcessFault}; + + kout << "UserProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; + return ErrorOr<PID>{kProcessScheduler.CurrentProcess().Leak().ProcessId}; + } + + /// @brief Check if process can be schedulded. + /// @param process the process reference. + /// @retval true can be schedulded. + /// @retval false cannot be schedulded. + Bool UserProcessHelper::CanBeScheduled(const UserProcess& process) + { + if (process.Status == ProcessStatusKind::kKilled || + process.Status == ProcessStatusKind::kFinished || + process.Status == ProcessStatusKind::kStarting || + process.Status == ProcessStatusKind::kFrozen) + return No; + + if (process.Status == ProcessStatusKind::kInvalid) + return No; + + if (!process.Image.fCode) + return No; + + if (!process.Name[0]) + return No; + + // real time processes shouldn't wait that much. + if (process.Affinity == AffinityKind::kRealTime) + return Yes; + + return process.PTime < 1; + } + + /***********************************************************************************/ + /** + * @brief Start scheduling current AP. + */ + /***********************************************************************************/ + + SizeT UserProcessHelper::StartScheduling() + { + return kProcessScheduler.Run(); + } + + /***********************************************************************************/ + /** + * \brief Does a context switch in a CPU. + * \param the_stack the stackframe of the running app. + * \param new_pid the process's PID. + */ + /***********************************************************************************/ + + Bool UserProcessHelper::Switch(VoidPtr image, UInt8* stack, HAL::StackFramePtr frame_ptr, const PID& new_pid) + { + for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Capacity(); ++index) + { + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPInvalid || + HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPBoot) + continue; + + // A fallback is a special core for real-time tasks which needs immediate execution. + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPRealTime) + { + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity != AffinityKind::kRealTime) + continue; + + if (HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid)) + { + PTime prev_ptime = HardwareThreadScheduler::The()[index].Leak()->fPTime; + + HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + + PID prev_pid = UserProcessHelper::TheCurrentPID(); + UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; + + return YES; + } + + continue; + } + + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity == AffinityKind::kRealTime) + continue; + + //////////////////////////////////////////////////////////// + /// Prepare task switch. /// + //////////////////////////////////////////////////////////// + + Bool ret = HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid); + + //////////////////////////////////////////////////////////// + /// Rollback on fail. /// + //////////////////////////////////////////////////////////// + + if (!ret) + continue; + + UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; + + HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + HardwareThreadScheduler::The()[index].Leak()->Wake(YES); + + return Yes; + } + + return No; + } + + //////////////////////////////////////////////////////////// + /// @brief this checks if any process is on the team. + //////////////////////////////////////////////////////////// + UserProcessScheduler::operator bool() + { + return mTeam.AsArray().Count() > 0; + } + + //////////////////////////////////////////////////////////// + /// @brief this checks if no process is on the team. + //////////////////////////////////////////////////////////// + Bool UserProcessScheduler::operator!() + { + return mTeam.AsArray().Count() == 0; + } +} // namespace NeOS diff --git a/dev/kernel/src/UserProcessTeam.cc b/dev/kernel/src/UserProcessTeam.cc new file mode 100644 index 00000000..e0533ef1 --- /dev/null +++ b/dev/kernel/src/UserProcessTeam.cc @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file UserProcessTeam.cc +/// @brief Process teams implementation. +/***********************************************************************************/ + +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + UserProcessTeam::UserProcessTeam() + { + for (SizeT i = 0U; i < this->mProcessList.Count(); ++i) + { + this->mProcessList[i] = UserProcess(); + this->mProcessList[i].PTime = 0; + this->mProcessList[i].Status = ProcessStatusKind::kKilled; + } + + this->mProcessCount = 0UL; + } + + /***********************************************************************************/ + /// @brief UserProcess list array getter. + /// @return The list of process to schedule. + /***********************************************************************************/ + + Array<UserProcess, kSchedProcessLimitPerTeam>& UserProcessTeam::AsArray() + { + return this->mProcessList; + } + + /***********************************************************************************/ + /// @brief Get team ID. + /// @return The team's ID. + /***********************************************************************************/ + + ProcessID& UserProcessTeam::Id() noexcept + { + return this->mTeamId; + } + + /***********************************************************************************/ + /// @brief Get current process getter as Ref. + /// @return The current process header. + /***********************************************************************************/ + + Ref<UserProcess>& UserProcessTeam::AsRef() + { + return this->mCurrentProcess; + } +} // namespace NeOS + +// last rev 05-03-24 diff --git a/dev/kernel/src/Utils.cc b/dev/kernel/src/Utils.cc new file mode 100644 index 00000000..a362099a --- /dev/null +++ b/dev/kernel/src/Utils.cc @@ -0,0 +1,224 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Utils.h> + +namespace NeOS +{ + Int32 rt_string_cmp(const Char* src, const Char* cmp, Size size) + { + Int32 counter = 0; + + for (Size index = 0; index < size; ++index) + { + if (src[index] != cmp[index]) + ++counter; + } + + return counter; + } + + Void rt_zero_memory(voidPtr pointer, Size len) + { + rt_set_memory(pointer, 0, len); + } + + SizeT rt_string_len(const Char* str, SizeT _len) + { + SizeT len{0}; + + do + { + if (len > _len) + { + return _len; + } + + ++len; + } while (str[len] != '\0'); + + return len; + } + + Size rt_string_len(const Char* ptr) + { + SizeT cnt{0}; + + while (ptr[cnt] != 0) + ++cnt; + + return cnt; + } + + voidPtr rt_set_memory(voidPtr src, UInt32 value, Size len) + { + UInt32* start = reinterpret_cast<UInt32*>(src); + + while (len) + { + *start = value; + ++start; + --len; + } + + return (voidPtr)start; + } + + Int rt_move_memory(const voidPtr src, voidPtr dst, Size len) + { + Char* srcChr = reinterpret_cast<Char*>(src); + Char* dstChar = reinterpret_cast<Char*>(dst); + SizeT index = 0; + + while (index < len) + { + dstChar[index] = srcChr[index]; + srcChr[index] = 0; + + ++index; + } + + return 0; + } + + Int rt_copy_memory(const voidPtr src, voidPtr dst, Size len) + { + char* srcChr = reinterpret_cast<char*>(src); + char* dstChar = reinterpret_cast<char*>(dst); + Size index = 0; + + while (index < len) + { + dstChar[index] = srcChr[index]; + ++index; + } + + dstChar[index] = 0; + + return index; + } + + const Char* rt_alloc_string(const Char* src) + { + const Char* string = new Char[rt_string_len(src) + 1]; + + if (!string) + return nullptr; + + voidPtr v_src = reinterpret_cast<voidPtr>(const_cast<char*>(src)); + voidPtr v_dst = reinterpret_cast<voidPtr>(const_cast<char*>(string)); + + rt_copy_memory(v_src, v_dst, rt_string_len(src) + 1); + + return string; + } + + Int32 rt_to_uppercase(Int32 character) + { + if (character >= 'a' && character <= 'z') + return character - 0x20; + + return character; + } + + Int32 rt_is_alnum(Int32 character) + { + return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9'); + } + + Int32 rt_to_lower(Int32 character) + { + if (character >= 'A' && character <= 'Z') + return character + 0x20; + + return character; + } + + Boolean rt_is_space(Char chr) + { + return chr == ' '; + } + + Boolean rt_is_newln(Char chr) + { + return chr == '\n'; + } + + VoidPtr rt_string_in_string(const Char* in, const Char* needle) + { + for (SizeT i = 0; i < rt_string_len(in); ++i) + { + if (rt_string_cmp(in + i, needle, rt_string_len(needle)) == 0) + return reinterpret_cast<voidPtr>(const_cast<char*>(in + i)); + } + + return nullptr; + } + + Char rt_to_char(UInt64 base, Int32 limit) + { + const Char kNumbers[17] = "0123456789ABCDEF"; + return kNumbers[base % limit]; + } + + Bool rt_to_string(Char* str, UInt64 base, Int32 limit) + { +#ifdef __NE_AMD64__ + auto i = 0; + + auto final_number = base; + + auto mult = 1; + auto elems = 0L; + + base /= 10; + + while (base > 0) + { + elems++; + mult *= 10; + base /= 10; + } + + while (elems > -1) + { + final_number = (final_number % mult) * 10 + final_number / mult; + str[i] = rt_to_char(final_number, limit); + + --elems; + ++i; + } +#endif + + return YES; + } + + /// @brief Checks for a string start at the character. + + Char* rt_string_has_char(Char* str, const Char chr) + { + while (*str != chr) + { + ++str; + + if (*str == 0) + return nullptr; + } + + return str; + } +} // namespace NeOS + +EXTERN_C void* memset(void* dst, int c, long long unsigned int len) +{ + return NeOS::rt_set_memory(dst, c, len); +} + +EXTERN_C void* memcpy(void* dst, const void* src, long long unsigned int len) +{ + NeOS::rt_copy_memory(const_cast<void*>(src), dst, len); + return dst; +} diff --git a/dev/kernel/src/Variant.cc b/dev/kernel/src/Variant.cc new file mode 100644 index 00000000..cfa29d3a --- /dev/null +++ b/dev/kernel/src/Variant.cc @@ -0,0 +1,41 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Variant.h> + +namespace NeOS +{ + const Char* Variant::ToString() + { + switch (fKind) + { + case VariantKind::kXML: + return ("Class:{XML}"); + case VariantKind::kJson: + return ("Class:{Json}"); + case VariantKind::kString: + return ("Class:{String}"); + case VariantKind::kBlob: + return ("Class:{Blob}"); + case VariantKind::kNull: + return ("Class:{Null}"); + default: + return ("Class:{Unknown}"); + } + } + + /// @brief Return variant's kind. + Variant::VariantKind& Variant::Kind() + { + return this->fKind; + } + + /// @brief Leak variant's instance. + VoidPtr Variant::Leak() + { + return this->fPtr; + } +} // namespace NeOS |
