diff options
Diffstat (limited to 'Kernel/Source')
57 files changed, 5198 insertions, 0 deletions
diff --git a/Kernel/Source/AppMain.cxx b/Kernel/Source/AppMain.cxx new file mode 100644 index 00000000..b91d6082 --- /dev/null +++ b/Kernel/Source/AppMain.cxx @@ -0,0 +1,193 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: AppMain.cxx + Purpose: Kernel main loop. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <Builtins/Toolbox/Toolbox.hxx> +#include <CompilerKit/Detail.hxx> +#include <FirmwareKit/Handover.hxx> +#include <KernelKit/FileManager.hpp> +#include <KernelKit/Framebuffer.hpp> +#include <KernelKit/KernelHeap.hpp> +#include <KernelKit/PEF.hpp> +#include <KernelKit/PEFCodeManager.hxx> +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/UserHeap.hpp> +#include <NewKit/Json.hpp> +#include <NewKit/KernelCheck.hpp> +#include <NewKit/String.hpp> +#include <NewKit/Utils.hpp> + +namespace Detail +{ + /// @brief Filesystem auto mounter, additional checks are also done by the + /// class. + class FilesystemWizard final + { + NewOS::NewFilesystemManager* fNewFS{nullptr}; + + public: + explicit FilesystemWizard() + { + if (NewOS::FilesystemManagerInterface::GetMounted()) + { + /// Mounted partition, cool! + NewOS::kcout + << "New OS: No need to create for a NewFS partition here...\r"; + } + else + { + /// Not mounted partition, auto-mount. + ///! Mounts a NewFS block. + fNewFS = new NewOS::NewFilesystemManager(); + + NewOS::FilesystemManagerInterface::Mount(fNewFS); + + if (fNewFS->GetImpl()) + { + constexpr auto cFolderInfo = "Metadata"; + const auto cDirCount = 8; + const char* cDirStr[cDirCount] = { + "/Boot/", "/System/", "/Support/", "/Applications/", + "/Users/", "/Library/", "/Mount/", "/Assistants/"}; + + for (NewOS::SizeT dirIndx = 0UL; dirIndx < cDirCount; ++dirIndx) + { + auto catalogDir = fNewFS->GetImpl()->GetCatalog(cDirStr[dirIndx]); + + if (catalogDir) + { + delete catalogDir; + continue; + } + + catalogDir = fNewFS->GetImpl()->CreateCatalog(cDirStr[dirIndx], 0, + kNewFSCatalogKindDir); + + NewFork theFork{0}; + + const NewOS::Char* cSrcName = cFolderInfo; + + NewOS::rt_copy_memory((NewOS::VoidPtr)(cSrcName), theFork.ForkName, + NewOS::rt_string_len(cSrcName)); + + NewOS::rt_copy_memory((NewOS::VoidPtr)(catalogDir->Name), + theFork.CatalogName, + NewOS::rt_string_len(catalogDir->Name)); + + delete catalogDir; + + theFork.DataSize = kNewFSForkSize; + theFork.ResourceId = 0; + theFork.ResourceKind = NewOS::kNewFSRsrcForkKind; + theFork.Kind = NewOS::kNewFSDataForkKind; + + NewOS::StringView metadataFolder(kNewFSSectorSz); + + metadataFolder += + "<p>Kind: folder</p>\r<p>Created by: system</p>\r<p>Edited by: " + "system</p>\r<p>Volume Type: New OS Standard</p>\r"; + + metadataFolder += "<p>File name: "; + metadataFolder += cDirStr[dirIndx]; + metadataFolder += "</p>\r"; + + const NewOS::SizeT metadataSz = kNewFSSectorSz; + + auto catalogSystem = fNewFS->GetImpl()->GetCatalog(cDirStr[dirIndx]); + + fNewFS->GetImpl()->CreateFork(catalogSystem, theFork); + + fNewFS->GetImpl()->WriteCatalog( + catalogSystem, (NewOS::VoidPtr)(metadataFolder.CData()), + metadataSz, cFolderInfo); + + delete catalogSystem; + } + } + + NewCatalog* catalogDisk = + this->fNewFS->GetImpl()->GetCatalog("/Mount/This Disk"); + + const NewOS::Char* cSrcName = "DiskInfo"; + + if (catalogDisk) + { + auto bufferInfoDisk = (NewOS::Char*)this->fNewFS->GetImpl()->ReadCatalog(catalogDisk, kNewFSSectorSz, cSrcName); + NewOS::kcout << bufferInfoDisk << NewOS::end_line(); + + delete bufferInfoDisk; + delete catalogDisk; + } + else + { + catalogDisk = + (NewCatalog*)this->Leak()->CreateAlias("/Mount/This Disk"); + + NewOS::StringView diskFolder(kNewFSSectorSz); + + diskFolder += + "<p>Kind: alias to disk</p>\r<p>Created by: system</p>\r<p>Edited " + "by: " + "system</p>\r<p>Volume Type: New OS Standard</p>\r"; + + diskFolder += "<p>Original Path: "; + diskFolder += NewOS::NewFilesystemHelper::Root(); + diskFolder += "</p>\r"; + + NewFork theDiskFork{0}; + + NewOS::rt_copy_memory((NewOS::VoidPtr)(cSrcName), theDiskFork.ForkName, + NewOS::rt_string_len(cSrcName)); + + NewOS::rt_copy_memory((NewOS::VoidPtr)(catalogDisk->Name), + theDiskFork.CatalogName, + NewOS::rt_string_len(catalogDisk->Name)); + + theDiskFork.DataSize = kNewFSForkSize; + theDiskFork.ResourceId = 0; + theDiskFork.ResourceKind = NewOS::kNewFSRsrcForkKind; + theDiskFork.Kind = NewOS::kNewFSDataForkKind; + + fNewFS->GetImpl()->CreateFork(catalogDisk, theDiskFork); + fNewFS->GetImpl()->WriteCatalog(catalogDisk, + (NewOS::VoidPtr)diskFolder.CData(), + kNewFSSectorSz, cSrcName); + + delete catalogDisk; + } + } + } + + ~FilesystemWizard() + { + delete fNewFS; + } + + NEWOS_COPY_DEFAULT(FilesystemWizard); + + /// Grab the disk's NewFS reference. + NewOS::NewFilesystemManager* Leak() + { + return fNewFS; + } + }; +} // namespace Detail + +/// @file Main microkernel entrypoint. + +EXTERN_C NewOS::Void AppMain(NewOS::Void) +{ + /// Now run kernel loop, until no process are running. + Detail::FilesystemWizard wizard; // automatic. + + while (NewOS::ProcessScheduler::Shared().Leak().Run() > 0) + { + ; + } +} diff --git a/Kernel/Source/Array.cxx b/Kernel/Source/Array.cxx new file mode 100644 index 00000000..618ba9f6 --- /dev/null +++ b/Kernel/Source/Array.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Array.hpp> diff --git a/Kernel/Source/ArrayList.cxx b/Kernel/Source/ArrayList.cxx new file mode 100644 index 00000000..0f3a1b3a --- /dev/null +++ b/Kernel/Source/ArrayList.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/ArrayList.hpp> diff --git a/Kernel/Source/Atom.cxx b/Kernel/Source/Atom.cxx new file mode 100644 index 00000000..f7ae9416 --- /dev/null +++ b/Kernel/Source/Atom.cxx @@ -0,0 +1,10 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Atom.hpp> + +// @file Atom.cpp +// @brief Atomic primitives diff --git a/Kernel/Source/CodeManager.cxx b/Kernel/Source/CodeManager.cxx new file mode 100644 index 00000000..39917163 --- /dev/null +++ b/Kernel/Source/CodeManager.cxx @@ -0,0 +1,29 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Utils.hpp> +#include <KernelKit/CodeManager.hpp> +#include <KernelKit/ProcessScheduler.hpp> + +using namespace NewOS; + +/// @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. +bool execute_from_image(MainKind main, const char* processName) noexcept +{ + if (!main) + return false; + + ProcessHeader proc((VoidPtr)main); + proc.Kind = ProcessHeader::kDriverKind; + rt_copy_memory((VoidPtr)processName, proc.Name, rt_string_len(proc.Name)); + + Ref<ProcessHeader> refProc = proc; + + return ProcessScheduler::Shared().Leak().Add(refProc); +}
\ No newline at end of file diff --git a/Kernel/Source/Crc32.cxx b/Kernel/Source/Crc32.cxx new file mode 100644 index 00000000..6ddb5642 --- /dev/null +++ b/Kernel/Source/Crc32.cxx @@ -0,0 +1,74 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Crc32.hpp> + +// @file CRC32.cpp +// @brief Check sequence implementation. + +namespace NewOS +{ + /// @brief The CRC32 table. + UInt kCrcTbl[kCrcCnt] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + + /// @brief Calculate CRC32 of p + /// @param p the data to compute. + /// @param len the length of the data. + /// @return the CRC32. + UInt ke_calculate_crc32(const Char* p, UInt len) noexcept + { + UInt crc = 0xffffffff; + + while (len-- != 0) + crc = kCrcTbl[((UInt8)crc ^ *(p++))] ^ (crc >> 8); + + // return (~crc); also works, does the same thing. + return (crc ^ 0xffffffff); + } +} // namespace NewOS diff --git a/Kernel/Source/CxxAbi.cxx b/Kernel/Source/CxxAbi.cxx new file mode 100644 index 00000000..2f9ae6a2 --- /dev/null +++ b/Kernel/Source/CxxAbi.cxx @@ -0,0 +1,87 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <NewKit/CxxAbi.hpp> +#include <NewKit/KernelCheck.hpp> + +atexit_func_entry_t __atexit_funcs[kDSOMaxObjects]; + +uarch_t __atexit_func_count; + +extern "C" void __cxa_pure_virtual() +{ + NewOS::kcout << "New OS: C++ placeholder method.\n"; +} + +extern "C" void ___chkstk_ms() +{ + while (1) + { + asm("cli"); + asm("hlt"); + } +} + +extern "C" int atexit(void (*f)(void*), void* arg, void* dso) +{ + if (__atexit_func_count >= kDSOMaxObjects) + 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 diff --git a/Kernel/Source/Defines.cxx b/Kernel/Source/Defines.cxx new file mode 100644 index 00000000..02327f07 --- /dev/null +++ b/Kernel/Source/Defines.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Defines.hpp> diff --git a/Kernel/Source/DeviceManager.cxx b/Kernel/Source/DeviceManager.cxx new file mode 100644 index 00000000..6e45e9da --- /dev/null +++ b/Kernel/Source/DeviceManager.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DeviceManager.hpp> diff --git a/Kernel/Source/DriveManager.cxx b/Kernel/Source/DriveManager.cxx new file mode 100644 index 00000000..c60b2079 --- /dev/null +++ b/Kernel/Source/DriveManager.cxx @@ -0,0 +1,149 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <KernelKit/DriveManager.hxx> +#include <Builtins/ATA/ATA.hxx> +#include <Builtins/AHCI/AHCI.hxx> +#include <NewKit/Utils.hpp> + +/// @file DriveManager.cxx +/// @brief Kernel drive manager. + +namespace NewOS +{ + static UInt16 kATAIO = 0U; + static UInt8 kATAMaster = 0U; + + /// @brief reads from an ATA drive. + /// @param pckt + /// @return + Void ke_drv_input(DriveTrait::DrivePacket* pckt) + { + if (!pckt) + { + return; + } + + pckt->fPacketGood = false; + +#ifdef __AHCI__ + drv_std_read(pckt->fLba, (Char*)pckt->fPacketContent, kAHCISectorSize, pckt->fPacketSize); +#elif defined(__ATA_PIO__) || defined(__ATA_DMA__) + drv_std_read(pckt->fLba, kATAIO, kATAMaster, (Char*)pckt->fPacketContent, kATASectorSize, pckt->fPacketSize); +#endif + + pckt->fPacketGood = true; + } + + /// @brief Writes to an ATA drive. + /// @param pckt + /// @return + Void ke_drv_output(DriveTrait::DrivePacket* pckt) + { + if (!pckt) + { + return; + } + + pckt->fPacketGood = false; + +#ifdef __AHCI__ + drv_std_write(pckt->fLba, (Char*)pckt->fPacketContent, kATASectorSize, pckt->fPacketSize); +#elif defined(__ATA_PIO__) || defined(__ATA_DMA__) + drv_std_write(pckt->fLba, kATAIO, kATAMaster, (Char*)pckt->fPacketContent, kATASectorSize, pckt->fPacketSize); +#endif + + pckt->fPacketGood = true; + } + + /// @brief Executes a disk check on the ATA drive. + /// @param pckt + /// @return + Void ke_drv_check_disk(DriveTrait::DrivePacket* pckt) + { + if (!pckt) + { + return; + } + + pckt->fPacketGood = false; + +#if defined(__ATA_PIO__) || defined(__ATA_DMA__) + kATAMaster = true; + kATAIO = ATA_PRIMARY_IO; + + MUST_PASS(drv_std_init(kATAIO, kATAMaster, kATAIO, kATAMaster)); +#endif // if defined(__ATA_PIO__) || defined (__ATA_DMA__) + + pckt->fPacketGood = true; + } + +/// @brief Gets the drive kind (ATA, SCSI, AHCI...) +/// @param +/// @return +#ifdef __ATA_PIO__ + const Char* ke_drive_kind(Void) + { + return "ATA-PIO"; + } +#endif + +#ifdef __ATA_DMA__ + const Char* ke_drive_kind(Void) + { + return "ATA-DMA"; + } +#endif + +#ifdef __AHCI__ + const Char* ke_drive_kind(Void) + { + return "AHCI"; + } +#endif + + /// @brief Unimplemented drive. + /// @param pckt + /// @return + Void ke_drv_unimplemented(DriveTrait::DrivePacket* pckt) + { + } + + /// @brief Makes a new drive. + /// @return the new drive. + DriveTrait construct_drive() noexcept + { + DriveTrait trait; + + rt_copy_memory((VoidPtr) "/Mount/Null", trait.fName, rt_string_len("/Mount/Null")); + trait.fKind = kInvalidDrive; + + trait.fInput = ke_drv_unimplemented; + trait.fOutput = ke_drv_unimplemented; + trait.fVerify = ke_drv_unimplemented; + trait.fDriveKind = ke_drive_kind; + + return trait; + } + + /// @brief Fetches the main drive. + /// @return the new drive. + DriveTrait construct_main_drive() noexcept + { + DriveTrait trait; + + rt_copy_memory((VoidPtr) "/Mount/MainDisk/", trait.fName, rt_string_len("/Mount/MainDisk/")); + trait.fKind = kMassStorage | kEPMDrive; + + trait.fInput = ke_drv_input; + trait.fOutput = ke_drv_output; + trait.fVerify = ke_drv_check_disk; + trait.fDriveKind = ke_drive_kind; + + return trait; + } +} // namespace NewOS diff --git a/Kernel/Source/ErrorOr.cxx b/Kernel/Source/ErrorOr.cxx new file mode 100644 index 00000000..7cef9afb --- /dev/null +++ b/Kernel/Source/ErrorOr.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/ErrorOr.hpp> + +/***********************************************************************************/ +/// @file ErrorOr.cxx /// +/// @brief Error Or Value class. /// +/***********************************************************************************/ diff --git a/Kernel/Source/FS/NewFS.cxx b/Kernel/Source/FS/NewFS.cxx new file mode 100644 index 00000000..41869fcd --- /dev/null +++ b/Kernel/Source/FS/NewFS.cxx @@ -0,0 +1,938 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#ifdef __FSKIT_NEWFS__ + +#include <Builtins/AHCI/AHCI.hxx> +#include <Builtins/ATA/ATA.hxx> +#include <FSKit/NewFS.hxx> +#include <KernelKit/HError.hpp> +#include <NewKit/Crc32.hpp> +#include <NewKit/KernelCheck.hpp> +#include <NewKit/String.hpp> +#include <NewKit/Utils.hpp> + +using namespace NewOS; + +///! BUGS: 0 + +/***********************************************************************************/ +/* This file implements the New File System. +/***********************************************************************************/ + +STATIC MountpointInterface sMountpointInterface; + +/// @brief Creates a new fork inside the New filesystem partition. +/// @param catalog it's catalog +/// @param theFork the fork itself. +/// @return the fork +_Output NewFork* NewFSParser::CreateFork(_Input NewCatalog* catalog, + _Input NewFork& theFork) +{ + if (!sMountpointInterface.GetAddressOf(this->fDriveIndex)) + return nullptr; + + if (catalog && theFork.ForkName[0] != 0 && + theFork.DataSize == kNewFSForkSize) + { + Lba lba = (theFork.Kind == kNewFSDataForkKind) ? catalog->DataFork + : catalog->ResourceFork; + + kcout << "Fork Lba: " << hex_number(lba) << endl; + + if (lba <= kNewFSCatalogStartAddress) + return nullptr; + + auto drv = sMountpointInterface.GetAddressOf(this->fDriveIndex); + + /// special treatment. + rt_copy_memory((VoidPtr) "fs/newfs-packet", drv->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + NewFork curFork{0}; + NewFork prevFork{0}; + Lba lbaOfPreviousFork = lba; + + /// do not check for anything. Loop until we get what we want, that is a free fork zone. + while (true) + { + if (lba <= kNewFSCatalogStartAddress) + break; + + drv->fPacket.fLba = lba; + drv->fPacket.fPacketSize = sizeof(NewFork); + drv->fPacket.fPacketContent = &curFork; + + drv->fInput(&drv->fPacket); + + kcout << "New OS: Next-Fork: " << hex_number(curFork.NextSibling) << endl; + + if (curFork.Flags == kNewFSFlagCreated) + { + kcout << "New OS: Fork already exists.\r"; + + /// sanity check. + if (StringBuilder::Equals(curFork.ForkName, theFork.ForkName) && + StringBuilder::Equals(curFork.CatalogName, catalog->Name)) + return nullptr; + + kcout << "Next-Fork: " << hex_number(curFork.NextSibling) << endl; + + lbaOfPreviousFork = lba; + lba = curFork.NextSibling; + + prevFork = curFork; + } + else + { + /// This is a check that we have, in order to link the previous fork + /// entry. + if (lba >= kNewFSCatalogStartAddress) + { + drv->fPacket.fLba = lbaOfPreviousFork; + drv->fPacket.fPacketSize = sizeof(NewFork); + drv->fPacket.fPacketContent = &prevFork; + + prevFork.NextSibling = lba; + + /// write to disk. + drv->fOutput(&drv->fPacket); + } + + break; + } + } + + constexpr auto cForkPadding = + 4; /// this value gives us space for the data offset. + + theFork.Flags = kNewFSFlagCreated; + theFork.DataOffset = lba - sizeof(NewFork) * cForkPadding; + theFork.PreviousSibling = lbaOfPreviousFork; + theFork.NextSibling = theFork.DataOffset - theFork.DataSize; + + drv->fPacket.fLba = lba; + drv->fPacket.fPacketSize = sizeof(NewFork); + drv->fPacket.fPacketContent = &theFork; + + drv->fOutput(&drv->fPacket); + + /// log what we have now. + kcout << "New OS: Wrote fork data at: " << hex_number(theFork.DataOffset) + << endl; + + kcout << "New OS: Wrote fork at: " << hex_number(lba) << endl; + + return &theFork; + } + + return nullptr; +} + +/// @brief Find fork inside New filesystem. +/// @param catalog the catalog. +/// @param name the fork name. +/// @return the fork. +_Output NewFork* NewFSParser::FindFork(_Input NewCatalog* catalog, + _Input const Char* name, + Boolean isDataFork) +{ + auto drv = sMountpointInterface.GetAddressOf(this->fDriveIndex); + NewFork* theFork = nullptr; + + Lba lba = isDataFork ? catalog->DataFork : catalog->ResourceFork; + + while (lba != 0) + { + drv->fPacket.fLba = lba; + drv->fPacket.fPacketSize = sizeof(NewFork); + drv->fPacket.fPacketContent = (VoidPtr)theFork; + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drv->fPacket.fPacketMime, 16); + + if (auto res = + fs_newfs_read(&sMountpointInterface, *drv, this->fDriveIndex); + res) + { + switch (res) + { + case 1: + DbgLastError() = kErrorDiskReadOnly; + break; + case 2: + DbgLastError() = kErrorDiskIsFull; + break; + DbgLastError() = kErrorNoSuchDisk; + break; + + default: + break; + } + return nullptr; + } + + if (StringBuilder::Equals(theFork->ForkName, name)) + { + break; + } + + lba = theFork->NextSibling; + } + + return theFork; +} + +/// @brief Simpler factory to create a catalog (assumes you want to create a +/// file.) +/// @param name +/// @return catalog pointer. +_Output NewCatalog* NewFSParser::CreateCatalog(_Input const char* name) +{ + return this->CreateCatalog(name, 0, kNewFSCatalogKindFile); +} + +/// @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 NewCatalog* NewFSParser::CreateCatalog(_Input const char* name, + _Input const Int32& flags, + _Input const Int32& kind) +{ + if (!sMountpointInterface.GetAddressOf(this->fDriveIndex)) + return nullptr; + + Lba outLba = 0UL; + + /// a directory should have a slash in the end. + if (kind == kNewFSCatalogKindDir && + name[rt_string_len(name) - 1] != NewFilesystemHelper::Separator()) + return nullptr; + + /// a file shouldn't have a slash in the end. + if (kind != kNewFSCatalogKindDir && + name[rt_string_len(name) - 1] == NewFilesystemHelper::Separator()) + return nullptr; + + NewCatalog* checkForCpy = this->FindCatalog(name, outLba); + + if (checkForCpy) + { + return checkForCpy; + } + + char parentName[kNewFSNodeNameLen] = {0}; + + for (SizeT indexName = 0UL; indexName < rt_string_len(name); ++indexName) + { + parentName[indexName] = name[indexName]; + } + + if (*parentName == 0) + { + DbgLastError() = kErrorFileNotFound; + return nullptr; + } + + /// Locate parent catalog, to then allocate right after it. + + for (SizeT indexFill = 0; indexFill < rt_string_len(name); ++indexFill) + { + parentName[indexFill] = name[indexFill]; + } + + SizeT indexReverseCopy = rt_string_len(parentName); + + // zero character. + parentName[--indexReverseCopy] = 0; + + // mandatory / character. + parentName[--indexReverseCopy] = 0; + + while (parentName[indexReverseCopy] != NewFilesystemHelper::Separator()) + { + parentName[indexReverseCopy] = 0; + --indexReverseCopy; + } + + NewCatalog* catalog = this->FindCatalog(parentName, outLba); + + if (catalog && catalog->Kind == kNewFSCatalogKindFile) + { + delete catalog; + return nullptr; + } + else if (!catalog) + { + outLba = kNewFSCatalogStartAddress; + } + + constexpr SizeT cDefaultForkSize = kNewFSForkSize; + + NewCatalog* catalogChild = new NewCatalog(); + + catalogChild->ResourceForkSize = cDefaultForkSize; + catalogChild->DataForkSize = cDefaultForkSize; + + catalogChild->NextSibling = outLba; + catalogChild->PrevSibling = outLba; + catalogChild->Kind = kind; + catalogChild->Flags = kNewFSFlagCreated; + + rt_copy_memory((VoidPtr)name, (VoidPtr)catalogChild->Name, + rt_string_len(name)); + + UInt16 catalogBuf[kNewFSSectorSz] = {0}; + + auto drive = sMountpointInterface.GetAddressOf(this->fDriveIndex); + + Lba startFree = outLba; + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + drive->fPacket.fPacketContent = catalogBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = startFree; + + drive->fInput(&drive->fPacket); + + NewCatalog* nextSibling = (NewCatalog*)catalogBuf; + + startFree = nextSibling->NextSibling; + + catalogChild->PrevSibling = outLba; + + drive->fPacket.fLba = startFree; + drive->fInput(&drive->fPacket); + + while (drive->fPacket.fPacketGood) + { + nextSibling = (NewCatalog*)catalogBuf; + + if (startFree <= kNewFSAddressAsLba) + { + delete catalogChild; + delete catalog; + + return nullptr; + } + + /// allocation or reallocation or catalog... + if (nextSibling->Flags != kNewFSFlagCreated) + { + Char sectorBufPartBlock[kNewFSSectorSz] = {0}; + + drive->fPacket.fPacketContent = sectorBufPartBlock; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = kNewFSAddressAsLba; + + drive->fInput(&drive->fPacket); + + constexpr auto cNewFSCatalogPadding = 4; + + NewPartitionBlock* partBlock = (NewPartitionBlock*)sectorBufPartBlock; + + if (partBlock->FreeCatalog < 1) + { + delete catalogChild; + return nullptr; + } + + catalogChild->DataFork = partBlock->DiskSize - partBlock->StartCatalog; + + catalogChild->ResourceFork = catalogChild->DataFork; + + catalogChild->NextSibling = + startFree + (sizeof(NewCatalog) * cNewFSCatalogPadding); + + drive->fPacket.fPacketContent = catalogChild; + drive->fPacket.fPacketSize = sizeof(NewCatalog); + drive->fPacket.fLba = startFree; + + drive->fOutput(&drive->fPacket); + + drive->fPacket.fPacketContent = catalogBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = + startFree - (sizeof(NewCatalog) * cNewFSCatalogPadding); + + drive->fInput(&drive->fPacket); + + nextSibling->NextSibling = startFree; + + drive->fOutput(&drive->fPacket); + + kcout << "New OS: Create new catalog, status: " + << hex_number(catalogChild->Flags) << endl; + kcout << "New OS: Create new catalog, status: " << catalogChild->Name + << endl; + + drive->fPacket.fPacketContent = sectorBufPartBlock; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = kNewFSAddressAsLba; + + drive->fInput(&drive->fPacket); + + partBlock->SectorCount -= 1; + partBlock->CatalogCount += 1; + partBlock->FreeCatalog -= 1; + partBlock->FreeCatalog = catalogChild->NextSibling; + + drive->fOutput(&drive->fPacket); + + delete catalog; + return catalogChild; + } + + constexpr auto cNewFSCatalogPadding = 4; + + //// @note that's how we find the next catalog in the partition block. + startFree = startFree + (sizeof(NewCatalog) * cNewFSCatalogPadding); + + drive->fPacket.fPacketContent = catalogBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = startFree; + + drive->fInput(&drive->fPacket); + } + + delete catalog; + return nullptr; +} + +/// @brief Make a EPM+NewFS drive out of the disk. +/// @param drive The drive to write on. +/// @return If it was sucessful, see DbgLastError(). +bool NewFSParser::Format(_Input _Output DriveTrait* drive) +{ + /// verify disk. + drive->fVerify(&drive->fPacket); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + /// if disk isn't good, then error out. + if (false == drive->fPacket.fPacketGood) + { + DbgLastError() = kErrorDiskIsCorrupted; + return false; + } + + Char sectorBuf[kNewFSSectorSz] = {0}; + + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = kNewFSAddressAsLba; + + drive->fInput(&drive->fPacket); + + /// disk isnt faulty and data has been fetched. + if (drive->fPacket.fPacketGood) + { + NewPartitionBlock* partBlock = (NewPartitionBlock*)sectorBuf; + + /// check for an empty partition here. + if (partBlock->PartitionName[0] == 0 && + rt_string_cmp(partBlock->Ident, kNewFSIdent, kNewFSIdentLen)) + { + /// partition is free and valid. + + partBlock->Version = kNewFSVersionInteger; + + const auto cUntitledHD = "New OS HD\0"; + + rt_copy_memory((VoidPtr)kNewFSIdent, (VoidPtr)partBlock->Ident, + kNewFSIdentLen); + + rt_copy_memory((VoidPtr)cUntitledHD, (VoidPtr)partBlock->PartitionName, + rt_string_len(cUntitledHD)); + + SizeT catalogCount = 0; + SizeT sectorCount = drv_std_get_sector_count(); + SizeT diskSize = drv_std_get_drv_size(); + + partBlock->Kind = kNewFSPartitionTypeStandard; + partBlock->StartCatalog = kNewFSCatalogStartAddress; + partBlock->Flags = kNewFSPartitionTypeStandard; + partBlock->CatalogCount = sectorCount / sizeof(NewCatalog); + partBlock->SectorCount = sectorCount; + partBlock->DiskSize = diskSize; + partBlock->FreeCatalog = sectorCount / sizeof(NewCatalog); + + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = kNewFSAddressAsLba; + + drive->fOutput(&drive->fPacket); + + kcout << "Drive-Kind: " << drive->fDriveKind() << endl; + + kcout << "Partition-Name: " << partBlock->PartitionName << endl; + kcout << "Start-Catalog: " << hex_number(partBlock->StartCatalog) << endl; + kcout << "Catalog-Count: " << hex_number(partBlock->CatalogCount) << endl; + kcout << "Free-Catalog: " << hex_number(partBlock->FreeCatalog) << endl; + kcout << "Free-Sectors: " << hex_number(partBlock->FreeSectors) << endl; + kcout << "Sector-Size: " << hex_number(partBlock->SectorSize) << endl; + + /// write the root catalog. + this->CreateCatalog(kNewFSRoot, 0, kNewFSCatalogKindDir); + + return true; + } + + kcout << "New OS: PartitionBlock already exists.\r"; + + /// return success as well, do not ignore that partition. + return true; + } + + 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 NewFSParser::WriteCatalog(_Input _Output NewCatalog* catalog, voidPtr data, SizeT sizeOfData, _Input const char* forkName) +{ + if (sizeOfData > catalog->DataForkSize) + return false; + if (!sMountpointInterface.GetAddressOf(this->fDriveIndex)) + return false; + + NewFork* forkData = new NewFork(); + rt_set_memory(forkData, 0, sizeof(NewFork)); + + auto drive = sMountpointInterface.GetAddressOf(this->fDriveIndex); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + auto startFork = catalog->DataFork; + + rt_copy_memory(catalog->Name, forkData->CatalogName, kNewFSNodeNameLen); + + /// sanity check of the fork position as the condition to run the loop. + while (startFork >= kNewFSCatalogStartAddress) + { + drive->fPacket.fPacketContent = forkData; + drive->fPacket.fPacketSize = sizeof(NewFork); + drive->fPacket.fLba = startFork; + + drive->fInput(&drive->fPacket); + + kcout << "Fork-Name: " << forkData->ForkName << endl; + + /// sanity check the fork. + if (forkData->DataOffset <= kNewFSCatalogStartAddress) + { + DbgLastError() = kErrorDiskIsCorrupted; + + kcout << "New OS: Invalid fork offset.\r"; + + delete forkData; + return false; + } + + if (forkData->Flags != kNewFSFlagUnallocated && + forkData->Flags != kNewFSFlagDeleted && + StringBuilder::Equals(forkData->ForkName, forkName) && + StringBuilder::Equals(forkData->CatalogName, catalog->Name)) + { + drive->fPacket.fPacketContent = data; + drive->fPacket.fPacketSize = sizeOfData; + drive->fPacket.fLba = forkData->DataOffset; + kcout << "Fork-Offset: " << hex_number(forkData->DataOffset) << endl; + + drive->fOutput(&drive->fPacket); + + delete forkData; + return true; + } + else if (auto catalog = this->GetCatalog(forkData->CatalogName); + catalog == nullptr) + { + delete catalog; + drive->fPacket.fPacketContent = data; + drive->fPacket.fPacketSize = sizeOfData; + drive->fPacket.fLba = forkData->DataOffset; + kcout << "Fork-Offset: " << hex_number(forkData->DataOffset) << endl; + + drive->fOutput(&drive->fPacket); + + delete forkData; + return true; + } + + startFork = forkData->NextSibling; + } + + delete forkData; + return false; +} + +/// @brief +/// @param catalogName the catalog name. +/// @return the newly found catalog. +_Output NewCatalog* NewFSParser::FindCatalog(_Input const char* catalogName, + Lba& outLba) +{ + if (!sMountpointInterface.GetAddressOf(this->fDriveIndex)) + return nullptr; + + Char* sectorBuf = new Char[sizeof(NewPartitionBlock)]; + auto drive = sMountpointInterface.GetAddressOf(this->fDriveIndex); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = sizeof(NewPartitionBlock); + drive->fPacket.fLba = kNewFSAddressAsLba; + + drive->fInput(&drive->fPacket); + + NewPartitionBlock* part = (NewPartitionBlock*)sectorBuf; + + auto startCatalogList = part->StartCatalog; + const auto cCtartCatalogList = part->StartCatalog; + + auto localSearchFirst = false; + + drive->fPacket.fLba = startCatalogList; + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = sizeof(NewCatalog); + + drive->fInput(&drive->fPacket); + + if (!StringBuilder::Equals(catalogName, NewFilesystemHelper::Root())) + { + Char parentName[kNewFSNodeNameLen] = {0}; + + for (SizeT indexFill = 0; indexFill < rt_string_len(catalogName); ++indexFill) + { + parentName[indexFill] = catalogName[indexFill]; + } + + SizeT indexReverseCopy = rt_string_len(parentName); + + // zero character. + parentName[--indexReverseCopy] = 0; + + // mandatory '/' character. + parentName[--indexReverseCopy] = 0; + + while (parentName[indexReverseCopy] != NewFilesystemHelper::Separator()) + { + parentName[indexReverseCopy] = 0; + --indexReverseCopy; + } + + NewCatalog* parentCatalog = this->FindCatalog(parentName, outLba); + + if (parentCatalog && + !StringBuilder::Equals(parentName, NewFilesystemHelper::Root())) + { + startCatalogList = outLba; + delete parentCatalog; + + localSearchFirst = true; + } + else if (parentCatalog) + { + delete parentCatalog; + } + } + +_NewFSSearchThroughCatalogList: + while (drive->fPacket.fPacketGood) + { + NewCatalog* catalog = (NewCatalog*)sectorBuf; + + if (StringBuilder::Equals(catalogName, catalog->Name)) + { + /// ignore unallocated catalog, break + if (catalog->Flags != kNewFSFlagCreated) + { + goto _NewFSContinueSearch; + } + + NewCatalog* catalogPtr = new NewCatalog(); + rt_copy_memory(catalog, catalogPtr, sizeof(NewCatalog)); + + kcout << "New OS: Found catalog at: " << hex_number(startCatalogList) << endl; + + outLba = startCatalogList; + delete[] sectorBuf; + return catalogPtr; + } + + _NewFSContinueSearch: + startCatalogList = catalog->NextSibling; + + if (startCatalogList <= kNewFSAddressAsLba) + break; + + drive->fPacket.fLba = startCatalogList; + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = sizeof(NewCatalog); + + drive->fInput(&drive->fPacket); + } + + if (localSearchFirst) + { + localSearchFirst = false; + startCatalogList = cCtartCatalogList; + + goto _NewFSSearchThroughCatalogList; + } + + outLba = 0UL; + delete[] sectorBuf; + + return nullptr; +} + +/// @brief +/// @param name +/// @return +_Output NewCatalog* NewFSParser::GetCatalog(_Input const char* name) +{ + Lba unused = 0; + return this->FindCatalog(name, unused); +} + +/// @brief +/// @param catalog +/// @return +Boolean NewFSParser::CloseCatalog(_Input _Output NewCatalog* 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. +Boolean NewFSParser::RemoveCatalog(_Input const Char* catalogName) +{ + if (!catalogName || + StringBuilder::Equals(catalogName, NewFilesystemHelper::Root())) + { + DbgLastError() = kErrorInternal; + return false; + } + + Lba outLba = 0; + auto catalog = this->FindCatalog(catalogName, outLba); + + if (outLba >= kNewFSCatalogStartAddress || + catalog->Flags == kNewFSFlagCreated) + { + catalog->Flags = kNewFSFlagDeleted; + + auto drive = sMountpointInterface.GetAddressOf(this->fDriveIndex); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + drive->fPacket.fLba = outLba; // the catalog position. + drive->fPacket.fPacketSize = + sizeof(NewCatalog); // size of catalog. roughly the sector size. + drive->fPacket.fPacketContent = catalog; // the catalog itself. + + drive->fOutput(&drive->fPacket); // send packet. + + Char partitionBlockBuf[sizeof(NewPartitionBlock)] = {0}; + + drive->fPacket.fLba = kNewFSAddressAsLba; + drive->fPacket.fPacketContent = partitionBlockBuf; + drive->fPacket.fPacketSize = sizeof(NewPartitionBlock); + + drive->fInput(&drive->fPacket); + + NewPartitionBlock* partBlock = + reinterpret_cast<NewPartitionBlock*>(partitionBlockBuf); + + ++partBlock->FreeCatalog; + --partBlock->CatalogCount; + + drive->fOutput(&drive->fPacket); + + return true; + } + + delete catalog; + 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 NewFSParser::ReadCatalog(_Input _Output NewCatalog* catalog, + _Input SizeT dataSz, + _Input const char* forkName) +{ + if (!catalog) + { + DbgLastError() = kErrorFileNotFound; + return nullptr; + } + + if (!sMountpointInterface.GetAddressOf(this->fDriveIndex)) + return nullptr; + + Lba dataForkLba = catalog->DataFork; + Size dataForkSize = catalog->DataForkSize; + + kcout << "Found-Catalog: " << catalog->Name + << ", Data-Fork: " << hex_number(dataForkLba) << endl; + + Char* sectorBuf = new Char[sizeof(NewFork)]; + auto drive = sMountpointInterface.GetAddressOf(this->fDriveIndex); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + NewFork* forkData = nullptr; + + while (dataForkLba >= kNewFSCatalogStartAddress) + { + drive->fPacket.fLba = dataForkLba; + drive->fPacket.fPacketSize = sizeof(NewFork); + drive->fPacket.fPacketContent = sectorBuf; + + drive->fInput(&drive->fPacket); + + forkData = (NewFork*)sectorBuf; + + kcout << "Fork-Name: " << forkData->ForkName << endl; + + if (forkData->DataOffset <= kNewFSCatalogStartAddress) + { + delete[] sectorBuf; + + kcout << "Fail-Data-Offset: " << hex_number(forkData->DataOffset) << endl; + + return nullptr; + } + + if (StringBuilder::Equals(forkName, forkData->ForkName) && + StringBuilder::Equals(catalog->Name, forkData->CatalogName)) + break; + + dataForkLba = forkData->NextSibling; + } + + if (dataForkLba <= kNewFSCatalogStartAddress) + { + delete[] sectorBuf; + return nullptr; + } + + Char* forkBuf = new Char[dataSz]; + + drive->fPacket.fLba = forkData->DataOffset; + drive->fPacket.fPacketSize = dataSz; + drive->fPacket.fPacketContent = forkBuf; + + drive->fInput(&drive->fPacket); + + delete[] sectorBuf; + return forkBuf; +} + +/***********************************************************************************/ +/// @brief Seek in the data fork. +/// @param catalog the catalog offset. +/// @param off where to seek. +/// @return if the seeking was successful. +/***********************************************************************************/ + +bool NewFSParser::Seek(_Input _Output NewCatalog* catalog, SizeT off) +{ + if (!catalog) + { + DbgLastError() = kErrorFileNotFound; + return false; + } + + DbgLastError() = kErrorUnimplemented; + return false; +} + +/***********************************************************************************/ +/// @brief Tell where we are inside the data fork. +/// @param catalog +/// @return The position on the file. +/***********************************************************************************/ + +SizeT NewFSParser::Tell(_Input _Output NewCatalog* catalog) +{ + if (!catalog) + { + DbgLastError() = kErrorFileNotFound; + return 0; + } + + DbgLastError() = kErrorUnimplemented; + return 0; +} + +namespace NewOS::Detail +{ + /***********************************************************************************/ + /// @brief Construct NewFS drives. + /***********************************************************************************/ + Boolean fs_init_newfs(Void) noexcept + { + sMountpointInterface.A() = construct_main_drive(); + sMountpointInterface.B() = construct_drive(); + sMountpointInterface.C() = construct_drive(); + sMountpointInterface.D() = construct_drive(); + + sMountpointInterface.A().fVerify(&sMountpointInterface.A().fPacket); + + Char partitionBlockBuf[sizeof(NewPartitionBlock)] = {0}; + + sMountpointInterface.A().fPacket.fLba = kNewFSAddressAsLba; + sMountpointInterface.A().fPacket.fPacketContent = partitionBlockBuf; + sMountpointInterface.A().fPacket.fPacketSize = sizeof(NewPartitionBlock); + + sMountpointInterface.A().fInput(&sMountpointInterface.A().fPacket); + + NewPartitionBlock* partBlock = + reinterpret_cast<NewPartitionBlock*>(partitionBlockBuf); + + if (!StringBuilder::Equals(partBlock->Ident, kNewFSIdent)) + { + kcout << "New OS: New FS Partition is corrupt.\r"; + return false; + } + + kcout << "New OS: Read partition: " << partBlock->PartitionName << ", with success!\r"; + + return true; + } +} // namespace NewOS::Detail + +#endif // ifdef __FSKIT_NEWFS__ diff --git a/Kernel/Source/FileManager.cxx b/Kernel/Source/FileManager.cxx new file mode 100644 index 00000000..72ea15a1 --- /dev/null +++ b/Kernel/Source/FileManager.cxx @@ -0,0 +1,183 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/FileManager.hpp> +#include <NewKit/Utils.hpp> + +/// BUGS: 0 +//! @brief File manager for NewOS. + +namespace NewOS +{ + static FilesystemManagerInterface* kMounted = nullptr; + + /// @brief FilesystemManager getter. + /// @return The mounted filesystem. + FilesystemManagerInterface* FilesystemManagerInterface::GetMounted() + { + return kMounted; + } + + /// @brief Unmount filesystem. + /// @return The unmounted filesystem. + FilesystemManagerInterface* FilesystemManagerInterface::Unmount() + { + if (kMounted) + { + auto mount = kMounted; + kMounted = nullptr; + + return mount; + } + + return nullptr; + } + + /// @brief Mount filesystem. + /// @param mountPtr The filesystem to mount. + /// @return if it succeeded true, otherwise false. + bool FilesystemManagerInterface::Mount(FilesystemManagerInterface* mountPtr) + { + if (kMounted == nullptr) + { + kMounted = mountPtr; + return true; + } + + return false; + } + +#ifdef __FSKIT_NEWFS__ + /// @brief Opens a new file. + /// @param path + /// @param r + /// @return + NodePtr NewFilesystemManager::Open(const char* path, const char* r) + { + if (!path || *path == 0) + return nullptr; + + if (!r || *r == 0) + return nullptr; + + auto catalog = fImpl->GetCatalog(path); + + if (catalog->Kind != kNewFSCatalogKindFile) + { + fImpl->CloseCatalog(catalog); + return nullptr; + } + + 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 NewFilesystemManager::Write(NodePtr node, VoidPtr data, Int32 flags, SizeT size) + { + if (!size || + size > kNewFSForkSize) + return; + + if (!data) + return; + + NEWOS_UNUSED(flags); + + const char* cReadAllFork = fDataFork; + + if ((reinterpret_cast<NewCatalog*>(node))->Kind == kNewFSCatalogKindFile) + fImpl->WriteCatalog(reinterpret_cast<NewCatalog*>(node), data, size, + cReadAllFork); + } + + /// @brief Read from filesystem fork. + /// @param node the catalog node. + /// @param flags the flags with it. + /// @param sz the size to read. + /// @return + VoidPtr NewFilesystemManager::Read(NodePtr node, Int32 flags, SizeT sz) + { + if (sz > kNewFSForkSize) + return nullptr; + + if (!sz) + return nullptr; + + NEWOS_UNUSED(flags); + + const char* cReadAllFork = fDataFork; + + if ((reinterpret_cast<NewCatalog*>(node))->Kind == kNewFSCatalogKindFile) + return fImpl->ReadCatalog(reinterpret_cast<NewCatalog*>(node), sz, + cReadAllFork); + + 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. + + bool NewFilesystemManager::Seek(NodePtr node, SizeT off) + { + if (!node || off == 0) + return false; + + return fImpl->Seek(reinterpret_cast<NewCatalog*>(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. + + SizeT NewFilesystemManager::Tell(NodePtr node) + { + if (!node) + return kNPos; + + return fImpl->Tell(reinterpret_cast<NewCatalog*>(node)); + } + + /// @brief Rewinds the catalog. + /// @param node + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + bool NewFilesystemManager::Rewind(NodePtr node) + { + if (!node) + return false; + + return this->Seek(node, 0); + } + + /// @brief Returns the filesystem parser. + /// @return the Filesystem parser class. + NewFSParser* NewFilesystemManager::GetImpl() noexcept + { + return fImpl; + } + + void NewFilesystemManager::SetResourceFork(const char* forkName) + { + if (!forkName) return; + rt_copy_memory((VoidPtr)forkName, (VoidPtr)fRsrcFork, rt_string_len(forkName)); + } + + void NewFilesystemManager::SetDataFork(const char* forkName) + { + if (!forkName) return; + rt_copy_memory((VoidPtr)forkName, (VoidPtr)fDataFork, rt_string_len(forkName)); + } +#endif // __FSKIT_NEWFS__ +} // namespace NewOS diff --git a/Kernel/Source/Framebuffer.cxx b/Kernel/Source/Framebuffer.cxx new file mode 100644 index 00000000..7d36c722 --- /dev/null +++ b/Kernel/Source/Framebuffer.cxx @@ -0,0 +1,96 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: Framebuffer.cxx + Purpose: Framebuffer object + + Revision History: + + 01/02/24: Added file (amlel) + 02/02/24: Add documentation (amlel) + +------------------------------------------- */ + +#include <KernelKit/Framebuffer.hpp> + +/** + * @brief Framebuffer object implementation. + * + */ + +using namespace NewOS; + +namespace NewOS +{ + const UInt32 kRgbRed = 0x000000FF; + const UInt32 kRgbGreen = 0x0000FF00; + const UInt32 kRgbBlue = 0x00FF0000; + const UInt32 kRgbBlack = 0x00000000; + const UInt32 kRgbWhite = 0xFFFFFFFF; +} // namespace NewOS + +/** + * @brief Get Pixel at + * + * @param pos position of pixel. + * @return volatile* + */ +volatile UIntPtr* Framebuffer::operator[](const UIntPtr& pos) +{ + return (UIntPtr*)(fFrameBufferAddr->fBase * pos); +} + +/// @brief Boolean operator. +Framebuffer::operator bool() +{ + return fFrameBufferAddr.Leak()->fBase != 0 && + fColour != FramebufferColorKind::INVALID && + fFrameBufferAddr.Leak()->fBase != kBadPtr; +} + +/// @brief Set color kind of framebuffer. +/// @param colour +/// @return +const FramebufferColorKind& Framebuffer::Color( + const FramebufferColorKind& colour) +{ + if (fColour != FramebufferColorKind::INVALID && + colour != FramebufferColorKind::INVALID) + { + fColour = colour; + } + + return fColour; +} + +/// @brief Leak framebuffer context. +/// @return The reference of the framebuffer context. +Ref<FramebufferContext*>& Framebuffer::Leak() +{ + return this->fFrameBufferAddr; +} + +Framebuffer& Framebuffer::DrawRect(SizeT width, SizeT height, SizeT x, SizeT y, UInt32 color) +{ + for (NewOS::SizeT i = x; i < width + x; ++i) + { + for (NewOS::SizeT u = y; u < height + y; ++u) + { + *(((volatile NewOS::UInt32*)(fFrameBufferAddr.Leak()->fBase + + 4 * fFrameBufferAddr.Leak()->fBpp * i + + 4 * u))) = color; + } + } + + return *this; +} + +Framebuffer& Framebuffer::PutPixel(SizeT x, SizeT y, UInt32 color) +{ + *(((volatile NewOS::UInt32*)(fFrameBufferAddr.Leak()->fBase + + 4 * fFrameBufferAddr.Leak()->fBpp * x + + 4 * y))) = color; + + return *this; +}
\ No newline at end of file diff --git a/Kernel/Source/GUIDWizard.cxx b/Kernel/Source/GUIDWizard.cxx new file mode 100644 index 00000000..2e4ffafa --- /dev/null +++ b/Kernel/Source/GUIDWizard.cxx @@ -0,0 +1,65 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: GUIDWizard.cxx + Purpose: GUID helper code + + Revision History: + +------------------------------------------- */ + +#include <CFKit/GUIDWizard.hpp> +#include <NewKit/Ref.hpp> + +// begin of ascii 'readable' characters. (A, C, C, 1, 2) +#define kAsciiBegin 47 +// @brief Size of UUID. +#define kUUIDSize 37 + +namespace NewOS::XRN::Version1 +{ + auto make_sequence(const ArrayList<UShort>& uuidSeq) -> Ref<GUIDSequence*> + { + GUIDSequence* seq = new GUIDSequence(); + MUST_PASS(seq); + + Ref<GUIDSequence*> sequenceReference{seq, true}; + + sequenceReference->fMs1 |= uuidSeq[0]; + sequenceReference->fMs2 |= uuidSeq[1]; + sequenceReference->fMs3 |= uuidSeq[2]; + sequenceReference->fMs3 |= uuidSeq[3]; + + return sequenceReference; + } + + // @brief Tries to make a guid out of a string. + // This function is not complete for now + auto try_guid_to_string(Ref<GUIDSequence*>& seq) -> ErrorOr<Ref<StringView>> + { + Char buf[kUUIDSize]; + + for (SizeT index = 0; index < 16; ++index) + { + buf[index] = seq->u8[index] + kAsciiBegin; + } + + for (SizeT index = 16; index < 24; ++index) + { + buf[index] = seq->u16[index] + kAsciiBegin; + } + + for (SizeT index = 24; index < 28; ++index) + { + buf[index] = seq->u32[index] + kAsciiBegin; + } + + auto view = StringBuilder::Construct(buf); + + if (view) + return ErrorOr<Ref<StringView>>{view.Leak()}; + + return ErrorOr<Ref<StringView>>{-1}; + } +} // namespace NewOS::XRN::Version1 diff --git a/Kernel/Source/GUIDWrapper.cxx b/Kernel/Source/GUIDWrapper.cxx new file mode 100644 index 00000000..d8ed28e0 --- /dev/null +++ b/Kernel/Source/GUIDWrapper.cxx @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <CFKit/GUIDWrapper.hpp> + +namespace NewOS::XRN +{ +} diff --git a/Kernel/Source/HError.cxx b/Kernel/Source/HError.cxx new file mode 100644 index 00000000..bee5a467 --- /dev/null +++ b/Kernel/Source/HError.cxx @@ -0,0 +1,18 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/HError.hpp> + +namespace NewOS +{ + /// @brief Doea a system wide bug check. + /// @param void no params. + /// @return if error-free: true, otherwise false. + Boolean ke_bug_check(void) noexcept + { + return true; + } +} // namespace NewOS diff --git a/Kernel/Source/IndexableProperty.cxx b/Kernel/Source/IndexableProperty.cxx new file mode 100644 index 00000000..305d0988 --- /dev/null +++ b/Kernel/Source/IndexableProperty.cxx @@ -0,0 +1,57 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +//! @brief Filesystem Indexer. + +#include <CompilerKit/CompilerKit.hxx> +#include <FSKit/IndexableProperty.hxx> +#include <NewKit/MutableArray.hpp> +#include <NewKit/Utils.hpp> + +/// @brief File Indexer. +/// BUGS: 0 + +#define kMaxLenIndexer 256 + +namespace NewOS +{ + namespace Indexer + { + IndexProperty& IndexableProperty::LeakProperty() 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 path + /// @param filenameLen used bytes in path. + /// @param indexer the filesystem indexer. + /// @return none. + Void fs_index_file(const Char* filename, SizeT filenameLen, IndexableProperty& indexer) + { + if (!indexer.HasFlag(kIndexerClaimed)) + { + indexer.AddFlag(kIndexerClaimed); + rt_copy_memory((VoidPtr)indexer.LeakProperty().Path, (VoidPtr)filename, filenameLen); + + kcout << "New OS: FSKit: index new file: " << filename << endl; + } + } + } // namespace Indexer +} // namespace NewOS diff --git a/Kernel/Source/Json.cxx b/Kernel/Source/Json.cxx new file mode 100644 index 00000000..672c1b39 --- /dev/null +++ b/Kernel/Source/Json.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Json.hpp> + +using namespace NewOS; + +/// @brief Undefined object, is null in length. +INIT(NewOS::JsonType::kUndefined, NewOS::JsonType); diff --git a/Kernel/Source/KernelCheck.cxx b/Kernel/Source/KernelCheck.cxx new file mode 100644 index 00000000..e7c43650 --- /dev/null +++ b/Kernel/Source/KernelCheck.cxx @@ -0,0 +1,109 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <KernelKit/DebugOutput.hpp> +#include <NewKit/KernelCheck.hpp> +#include <NewKit/String.hpp> + +extern "C" [[noreturn]] void ke_wait_for_debugger() +{ + while (true) + { + NewOS::HAL::rt_cli(); + NewOS::HAL::rt_halt(); + } +} + +/* Each error code is attributed with an ID, which will prompt a string onto the + * screen. Wait for debugger... */ + +namespace NewOS +{ + void ke_stop(const NewOS::Int& id) + { + kcout << "*** STOP *** \r"; + kcout << "*** NewKernel.exe has trigerred a runtime stop. *** \r"; + + switch (id) + { + case RUNTIME_CHECK_PROCESS: { + kcout << "*** CAUSE: RUNTIME_CHECK_PROCESS *** \r"; + kcout << "*** WHAT: BAD DRIVER. *** \r"; + break; + } + case RUNTIME_CHECK_ACPI: { + kcout << "*** CAUSE: RUNTIME_CHECK_ACPI *** \r"; + kcout << "*** WHAT: ACPI ERROR, UNSTABLE STATE. *** \r"; + break; + } + case RUNTIME_CHECK_POINTER: { + kcout << "*** CAUSE: RUNTIME_CHECK_POINTER *** \r"; + kcout << "*** WHAT: HEAP CRC32 ERROR, UNSTABLE STATE. *** \r"; + break; + } + case RUNTIME_CHECK_BAD_BEHAVIOR: { + kcout << "*** CAUSE: RUNTIME_CHECK_BAD_BEHAVIOR *** \r"; + kcout << "*** WHAT: KERNEL BECAME UNSTABLE. *** \r"; + break; + } + case RUNTIME_CHECK_BOOTSTRAP: { + kcout << "*** CAUSE: RUNTIME_CHECK_BOOTSTRAP *** \r"; + kcout << "*** WHAT: INVALID BOOT SEQUENCE. *** \r"; + break; + } + case RUNTIME_CHECK_HANDSHAKE: { + kcout << "*** CAUSE: RUNTIME_CHECK_HANDSHAKE *** \r"; + kcout << "*** WHAT: BAD HANDSHAKE. *** \r"; + break; + } + case RUNTIME_CHECK_IPC: { + kcout << "*** CAUSE: RUNTIME_CHECK_IPC *** \r"; + kcout << "*** WHAT: RICH CALL VIOLATION. *** \r"; + break; + } + case RUNTIME_CHECK_INVALID_PRIVILEGE: { + kcout << "*** CAUSE: RUNTIME_CHECK_INVALID_PRIVILEGE *** \r"; + kcout << "*** WHAT: HYPERVISOR POLICY VIOLATION. *** \r"; + break; + case RUNTIME_CHECK_UNEXCPECTED: { + kcout << "*** CAUSE: RUNTIME_CHECK_UNEXCPECTED *** \r"; + kcout << "*** WHAT: CATASROPHIC FAILURE! *** \r"; + break; + } + case RUNTIME_CHECK_FAILED: { + kcout << "*** CAUSE: RUNTIME_CHECK_FAILED *** \r"; + kcout << "*** WHAT: ASSERTION FAILED! *** \r"; + break; + } + default: { + kcout << "*** CAUSE: RUNTIME_CHECK_GENERIC *** \r"; + break; + } + } + }; + + DumpManager::Dump(); + +#ifdef __DEBUG__ + ke_wait_for_debugger(); +#endif // ifdef __DEBUG__ + } + + void ke_runtime_check(bool expr, const char* file, const char* line) + { + if (!expr) + { +#ifdef __DEBUG__ + kcout << "New Kernel: File: " << file << "\r"; + kcout << "New Kernel: Line: " << line << "\r"; + +#endif // __DEBUG__ + + NewOS::ke_stop(RUNTIME_CHECK_FAILED); // Runtime Check failed + } + } +} // namespace NewOS diff --git a/Kernel/Source/KernelHeap.cxx b/Kernel/Source/KernelHeap.cxx new file mode 100644 index 00000000..d0037ec3 --- /dev/null +++ b/Kernel/Source/KernelHeap.cxx @@ -0,0 +1,169 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <KernelKit/HError.hpp> +#include <KernelKit/KernelHeap.hpp> +#include <NewKit/Crc32.hpp> +#include <NewKit/PageManager.hpp> + +//! @file KernelHeap.cxx +//! @brief Kernel allocator. + +#define kKernelHeapMagic (0xD4D7D5) +#define kKernelHeapHeaderPaddingSz (16U) + +namespace NewOS +{ + STATIC SizeT kHeapCount = 0UL; + STATIC PageManager kHeapPageManager; + + namespace Detail + { + /// @brief Kernel heap information block. + /// Located before the address bytes. + /// | HIB | ADDRESS | + struct PACKED HeapInformationBlock final + { + ///! @brief 32-bit value which contains the magic number of the executable. + UInt32 fMagic; + ///! @brief Boolean value which tells if the pointer is allocated. + Boolean fPresent; + ///! @brief 32-bit CRC checksum + UInt32 fCRC32; + /// @brief 64-bit pointer size. + SizeT fTargetPtrSize; + /// @brief 64-bit target pointer. + UIntPtr fTargetPtr; + UInt8 fPadding[kKernelHeapHeaderPaddingSz]; + }; + + typedef HeapInformationBlock* HeapInformationBlockPtr; + } // namespace Detail + + /// @brief allocate chunk of memory. + /// @param sz size of pointer + /// @param rw read write (true to enable it) + /// @param user is it accesible by user processes? + /// @return the pointer + VoidPtr ke_new_ke_heap(SizeT sz, const bool rw, const bool user) + { + if (sz == 0) + ++sz; + + auto wrapper = kHeapPageManager.Request(rw, user, false, sz); + + Detail::HeapInformationBlockPtr heapInfo = + reinterpret_cast<Detail::HeapInformationBlockPtr>( + wrapper.VirtualAddress()); + + heapInfo->fTargetPtrSize = sz; + heapInfo->fMagic = kKernelHeapMagic; + heapInfo->fCRC32 = 0; // dont fill it for now. + heapInfo->fTargetPtr = wrapper.VirtualAddress(); + + ++kHeapCount; + + return reinterpret_cast<VoidPtr>(wrapper.VirtualAddress() + + sizeof(Detail::HeapInformationBlock)); + } + + /// @brief Declare pointer as free. + /// @param heapPtr the pointer. + /// @return + Int32 ke_delete_ke_heap(VoidPtr heapPtr) + { + if (kHeapCount < 1) + return -kErrorInternal; + if (((IntPtr)heapPtr - sizeof(Detail::HeapInformationBlock)) <= 0) + return -kErrorInternal; + if (((IntPtr)heapPtr - kBadPtr) < 0) + return -kErrorInternal; + + Detail::HeapInformationBlockPtr virtualAddress = + reinterpret_cast<Detail::HeapInformationBlockPtr>( + (UIntPtr)heapPtr - sizeof(Detail::HeapInformationBlock)); + + if (virtualAddress && virtualAddress->fMagic == kKernelHeapMagic) + { + if (!virtualAddress->fPresent) + { + return -kErrorHeapNotPresent; + } + + if (virtualAddress->fCRC32 != 0) + { + if (virtualAddress->fCRC32 != + ke_calculate_crc32((Char*)virtualAddress->fTargetPtr, + virtualAddress->fTargetPtrSize)) + { + ke_stop(RUNTIME_CHECK_POINTER); + } + } + + virtualAddress->fTargetPtrSize = 0UL; + virtualAddress->fPresent = false; + virtualAddress->fTargetPtr = 0; + virtualAddress->fCRC32 = 0; + virtualAddress->fMagic = 0; + + PTEWrapper pageWrapper(false, false, false, (UIntPtr)virtualAddress); + Ref<PTEWrapper*> pteAddress{&pageWrapper}; + + kHeapPageManager.Free(pteAddress); + + --kHeapCount; + return 0; + } + + return -kErrorInternal; + } + + /// @brief Check if pointer is a valid kernel pointer. + /// @param heapPtr the pointer + /// @return if it exists. + Boolean ke_is_valid_heap(VoidPtr heapPtr) + { + if (kHeapCount < 1) + return false; + + if (heapPtr) + { + Detail::HeapInformationBlockPtr virtualAddress = + reinterpret_cast<Detail::HeapInformationBlockPtr>( + (UIntPtr)heapPtr - sizeof(Detail::HeapInformationBlock)); + + if (virtualAddress->fPresent && virtualAddress->fMagic == kKernelHeapMagic) + { + return true; + } + } + + return false; + } + + /// @brief Protect the heap with a CRC value. + /// @param heapPtr HIB pointer. + /// @return if it valid: point has crc now., otherwise fail. + Boolean ke_protect_ke_heap(VoidPtr heapPtr) + { + if (heapPtr) + { + Detail::HeapInformationBlockPtr virtualAddress = + reinterpret_cast<Detail::HeapInformationBlockPtr>( + (UIntPtr)heapPtr - sizeof(Detail::HeapInformationBlock)); + + if (virtualAddress->fPresent && kKernelHeapMagic == virtualAddress->fMagic) + { + virtualAddress->fCRC32 = + ke_calculate_crc32((Char*)heapPtr, virtualAddress->fTargetPtrSize); + return true; + } + } + + return false; + } +} // namespace NewOS diff --git a/Kernel/Source/LockDelegate.cxx b/Kernel/Source/LockDelegate.cxx new file mode 100644 index 00000000..70e421f7 --- /dev/null +++ b/Kernel/Source/LockDelegate.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/LockDelegate.hpp> + +namespace NewOS +{ + /// Leave it empty for now. +} // namespace NewOS
\ No newline at end of file diff --git a/Kernel/Source/MutableArray.cxx b/Kernel/Source/MutableArray.cxx new file mode 100644 index 00000000..047a4455 --- /dev/null +++ b/Kernel/Source/MutableArray.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/MutableArray.hpp> diff --git a/Kernel/Source/Network/IP.cxx b/Kernel/Source/Network/IP.cxx new file mode 100644 index 00000000..224f7b2a --- /dev/null +++ b/Kernel/Source/Network/IP.cxx @@ -0,0 +1,126 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NetworkKit/IP.hpp> +#include <NewKit/Utils.hpp> + +namespace NewOS +{ + 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) + { + kcout << "[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) + { + kcout << "[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<StringView> IPFactory::ToStringView(Ref<RawIPAddress6> ipv6) + { + auto str = StringBuilder::Construct(ipv6.Leak().Address()); + return str; + } + + ErrorOr<StringView> IPFactory::ToStringView(Ref<RawIPAddress> ipv4) + { + auto str = StringBuilder::Construct(ipv4.Leak().Address()); + return str; + } + + bool IPFactory::IpCheckVersion4(const char* ip) + { + int cnter = 0; + + for (Size base = 0; base < rt_string_len(ip); ++base) + { + if (ip[base] == '.') + { + cnter = 0; + } + else + { + if (cnter == 3) + return false; + + ++cnter; + } + } + + return true; + } +} // namespace NewOS diff --git a/Kernel/Source/Network/IPCEP.cxx b/Kernel/Source/Network/IPCEP.cxx new file mode 100644 index 00000000..39f3ea33 --- /dev/null +++ b/Kernel/Source/Network/IPCEP.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NetworkKit/IPCEP.hxx> diff --git a/Kernel/Source/Network/NetworkDevice.cxx b/Kernel/Source/Network/NetworkDevice.cxx new file mode 100644 index 00000000..a2c25782 --- /dev/null +++ b/Kernel/Source/Network/NetworkDevice.cxx @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NetworkKit/NetworkDevice.hpp> + +namespace NewOS +{ + const char* NetworkDevice::Name() const + { + return "NetworkDevice"; + } +} // namespace NewOS diff --git a/Kernel/Source/New+Delete.cxx b/Kernel/Source/New+Delete.cxx new file mode 100644 index 00000000..84e3a72d --- /dev/null +++ b/Kernel/Source/New+Delete.cxx @@ -0,0 +1,50 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/KernelHeap.hpp> +#include <NewKit/New.hpp> + +void* operator new[](size_t sz) +{ + if (sz == 0) + ++sz; + + return NewOS::ke_new_ke_heap(sz, true, false); +} + +void* operator new(size_t sz) +{ + if (sz == 0) + ++sz; + + return NewOS::ke_new_ke_heap(sz, true, false); +} + +void operator delete[](void* ptr) +{ + if (ptr == nullptr) + return; + + NewOS::ke_delete_ke_heap(ptr); +} + +void operator delete(void* ptr) +{ + if (ptr == nullptr) + return; + + NewOS::ke_delete_ke_heap(ptr); +} + +void operator delete(void* ptr, size_t sz) +{ + if (ptr == nullptr) + return; + + NEWOS_UNUSED(sz); + + NewOS::ke_delete_ke_heap(ptr); +} diff --git a/Kernel/Source/NewFS+FileManager.cxx b/Kernel/Source/NewFS+FileManager.cxx new file mode 100644 index 00000000..bcfc0443 --- /dev/null +++ b/Kernel/Source/NewFS+FileManager.cxx @@ -0,0 +1,89 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/FileManager.hpp> +#include <KernelKit/KernelHeap.hpp> + +#ifdef __FSKIT_NEWFS__ + +/// @brief NewFS File manager. +/// BUGS: 0 + +namespace NewOS +{ + /// @brief C++ constructor + NewFilesystemManager::NewFilesystemManager() + { + MUST_PASS(Detail::fs_init_newfs()); + fImpl = new NewFSParser(); + } + + NewFilesystemManager::~NewFilesystemManager() + { + if (fImpl) + { + delete fImpl; + } + } + + /// @brief Removes a node from the filesystem. + /// @param fileName The filename + /// @return If it was deleted or not. + bool NewFilesystemManager::Remove(const char* fileName) + { + if (fileName == nullptr || *fileName == 0) + return false; + + return fImpl->RemoveCatalog(fileName); + } + + /// @brief Creates a node with the specified. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NewFilesystemManager::Create(const char* path) + { + return node_cast(fImpl->CreateCatalog(path, 0, kNewFSCatalogKindFile)); + } + + /// @brief Creates a node with is a directory. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NewFilesystemManager::CreateDirectory(const char* path) + { + return node_cast(fImpl->CreateCatalog(path, 0, kNewFSCatalogKindDir)); + } + + /// @brief Creates a node with is a alias. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NewFilesystemManager::CreateAlias(const char* path) + { + return node_cast(fImpl->CreateCatalog(path, 0, kNewFSCatalogKindAlias)); + } + + /// @brief Gets the root directory. + /// @return + const char* NewFilesystemHelper::Root() + { + return kNewFSRoot; + } + + /// @brief Gets the up-dir directory. + /// @return + const char* NewFilesystemHelper::UpDir() + { + return kNewFSUpDir; + } + + /// @brief Gets the separator character. + /// @return + const char NewFilesystemHelper::Separator() + { + return kNewFSSeparator; + } +} // namespace NewOS + +#endif // ifdef __FSKIT_NEWFS__ diff --git a/Kernel/Source/NewFS+IO.cxx b/Kernel/Source/NewFS+IO.cxx new file mode 100644 index 00000000..3235c080 --- /dev/null +++ b/Kernel/Source/NewFS+IO.cxx @@ -0,0 +1,101 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DriveManager.hxx> +#include <KernelKit/FileManager.hpp> + +/************************************************************* + * + * File: NewFS+IO.cxx + * Purpose: Filesystem to mountpoint interface. + * Date: 3/26/24 + * + * Copyright SoftwareLabs, all rights reserved. + * + *************************************************************/ + +#ifdef __FSKIT_NEWFS__ + +#include <FirmwareKit/EPM.hxx> + +/// Useful macros. + +#define NEWFS_WRITE(DRV, TRAITS, MP) (MP->DRV()).fOutput(&TRAITS) +#define NEWFS_READ(DRV, TRAITS, MP) (MP->DRV()).fInput(&TRAITS) + +using namespace NewOS; + +/// @brief Read from newfs disk. +/// @param Mnt mounted interface. +/// @param DrvTrait drive info +/// @param DrvIndex drive index. +/// @return +Int32 fs_newfs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) +{ + if (!Mnt) + return -1; + + DrvTrait.fPacket.fPacketGood = false; + + switch (DrvIndex) + { + case kNewFSSubDriveA: { + NEWFS_READ(A, DrvTrait.fPacket, Mnt); + break; + } + case kNewFSSubDriveB: { + NEWFS_READ(B, DrvTrait.fPacket, Mnt); + break; + } + case kNewFSSubDriveC: { + NEWFS_READ(C, DrvTrait.fPacket, Mnt); + break; + } + case kNewFSSubDriveD: { + NEWFS_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_newfs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) +{ + if (!Mnt) + return -1; + + DrvTrait.fPacket.fPacketGood = false; + + switch (DrvIndex) + { + case kNewFSSubDriveA: { + NEWFS_WRITE(A, DrvTrait.fPacket, Mnt); + break; + } + case kNewFSSubDriveB: { + NEWFS_WRITE(B, DrvTrait.fPacket, Mnt); + break; + } + case kNewFSSubDriveC: { + NEWFS_WRITE(C, DrvTrait.fPacket, Mnt); + break; + } + case kNewFSSubDriveD: { + NEWFS_WRITE(D, DrvTrait.fPacket, Mnt); + break; + } + } + + return DrvTrait.fPacket.fPacketGood; +} + +#endif // ifdef __FSKIT_NEWFS__ diff --git a/Kernel/Source/NewFS+Journal.cxx b/Kernel/Source/NewFS+Journal.cxx new file mode 100644 index 00000000..23f42f89 --- /dev/null +++ b/Kernel/Source/NewFS+Journal.cxx @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <KernelKit/FileManager.hpp> + +#ifdef __FSKIT_NEWFS__ + +///! BUGS: 0 +///! @file NewFS+Journal.cxx +///! @brief Journaling for NewFS. + +namespace NewOS::Journal +{ +} // namespace NewOS::Journal + +using namespace NewOS; + +#endif // ifdef __FSKIT_NEWFS__ diff --git a/Kernel/Source/OwnPtr.cxx b/Kernel/Source/OwnPtr.cxx new file mode 100644 index 00000000..909eacef --- /dev/null +++ b/Kernel/Source/OwnPtr.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/OwnPtr.hpp> diff --git a/Kernel/Source/PEFCodeManager.cxx b/Kernel/Source/PEFCodeManager.cxx new file mode 100644 index 00000000..0bab5373 --- /dev/null +++ b/Kernel/Source/PEFCodeManager.cxx @@ -0,0 +1,226 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <KernelKit/FileManager.hpp> +#include <KernelKit/KernelHeap.hpp> +#include <KernelKit/PEFCodeManager.hxx> +#include <KernelKit/ProcessScheduler.hpp> +#include <NewKit/Defines.hpp> +#include <NewKit/KernelCheck.hpp> +#include <NewKit/OwnPtr.hpp> +#include <NewKit/String.hpp> + +namespace NewOS +{ + namespace Detail + { + /// @brief Get the PEF platform signature according to the compiled backebnd + UInt32 rt_get_pef_platform(void) noexcept + { +#ifdef __32x0__ + return kPefArch32x0; +#elif defined(__64x0__) + return kPefArch64x0; +#elif defined(__x86_64__) + return kPefArchAMD64; +#elif defined(__powerpc64__) + return kPefArchPowerPC; +#else + return kPefArchInvalid; +#endif // __32x0__ || __64x0__ || __x86_64__ + } + } // namespace Detail + + /// @brief PEF loader constructor w/ blob. + /// @param 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) + { + OwnPtr<FileStream<Char>> file; + + file.New(const_cast<Char*>(path), kRestrictRB); + + if (StringBuilder::Equals(file->MIME(), this->MIME())) + { + fPath = StringBuilder::Construct(path).Leak(); + + fCachedBlob = file->Read(); + + PEFContainer* container = reinterpret_cast<PEFContainer*>(fCachedBlob); + + if (container->Cpu == Detail::rt_get_pef_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[0] && container->Abi == kPefAbi) + { + /// This is a fat binary. + this->fFatBinary = true; + return; + } + + kcout << "CodeManager: Warning: Executable format error!\n"; + fBad = true; + + ke_delete_ke_heap(fCachedBlob); + + fCachedBlob = nullptr; + } + } + + /// @brief PEF destructor. + PEFLoader::~PEFLoader() + { + if (fCachedBlob) + ke_delete_ke_heap(fCachedBlob); + } + + VoidPtr PEFLoader::FindSymbol(const char* name, Int32 kind) + { + if (!fCachedBlob || fBad) + return nullptr; + + PEFContainer* container = reinterpret_cast<PEFContainer*>(fCachedBlob); + + PEFCommandHeader* container_header = reinterpret_cast<PEFCommandHeader*>( + (UIntPtr)fCachedBlob + sizeof(PEFContainer)); + + constexpr auto cMangleCharacter = '$'; + const char* cContainerKinds[] = {".code64", ".data64", ".zero64", nullptr}; + + ErrorOr<StringView> errOrSym; + + switch (kind) + { + case kPefCode: { + errOrSym = StringBuilder::Construct(cContainerKinds[0]); // code symbol. + break; + } + case kPefData: { + errOrSym = StringBuilder::Construct(cContainerKinds[1]); // data symbol. + break; + } + case kPefZero: { + errOrSym = StringBuilder::Construct(cContainerKinds[2]); // block starting symbol. + break; + } + default: + return nullptr; + } + + char* unconstSymbol = const_cast<char*>(name); + + for (SizeT i = 0UL; i < rt_string_len(unconstSymbol, kPefNameLen); ++i) + { + if (unconstSymbol[i] == ' ') + { + unconstSymbol[i] = cMangleCharacter; + } + } + + errOrSym.Leak().Leak() += name; + + for (SizeT index = 0; index < container->Count; ++index) + { + if (StringBuilder::Equals(container_header->Name, + errOrSym.Leak().Leak().CData())) + { + if (container_header->Kind == kind) + { + if (container_header->Cpu != Detail::rt_get_pef_platform()) + { + if (!this->fFatBinary) + return nullptr; + } + + return (VoidPtr)(static_cast<UIntPtr*>(fCachedBlob) + + container_header->Offset); + } + } + } + + 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; + } + + namespace Utils + { + bool execute_from_image(PEFLoader& exec, const Int32& procKind) noexcept + { + auto errOrStart = exec.FindStart(); + + if (errOrStart.Error() != 0) + return false; + + ProcessHeader proc(errOrStart.Leak().Leak()); + Ref<ProcessHeader> refProc = proc; + + proc.Kind = procKind; + + return ProcessScheduler::Shared().Leak().Add(refProc); + } + } // namespace Utils + + const char* PEFLoader::Path() + { + return fPath.Leak().CData(); + } + + const char* PEFLoader::FormatAsString() + { +#ifdef __32x0__ + return "32x0 PEF."; +#elif defined(__64x0__) + return "64x0 PEF."; +#elif defined(__x86_64__) + return "x86_64 PEF."; +#elif defined(__powerpc64__) + return "POWER PEF."; +#else + return "Unknown PEF."; +#endif // __32x0__ || __64x0__ || __x86_64__ || __powerpc64__ + } + + const char* PEFLoader::MIME() + { + return kPefApplicationMime; + } +} // namespace NewOS diff --git a/Kernel/Source/PEFSharedObjectRT.cxx b/Kernel/Source/PEFSharedObjectRT.cxx new file mode 100644 index 00000000..810f0480 --- /dev/null +++ b/Kernel/Source/PEFSharedObjectRT.cxx @@ -0,0 +1,107 @@ +/* + * ======================================================== + * + * NewOS + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#include <KernelKit/DebugOutput.hpp> +#include <KernelKit/PEF.hpp> +#include <KernelKit/PEFSharedObject.hxx> +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/ThreadLocalStorage.hxx> +#include <NewKit/Defines.hpp> + +/* ------------------------------------------- + + Revision History: + + 01/02/24: Rework shared library ABI, except a rt_library_init and + rt_library_free (amlel) 15/02/24: Breaking changes, changed the name of the + routines. (amlel) + + ------------------------------------------- */ + +using namespace NewOS; + +/***********************************************************************************/ +/// @file SharedObjectRT.cxx +/// @brief Shared Object runtime. +/***********************************************************************************/ + +/***********************************************************************************/ +/* @brief Library runtime initializer. */ +/***********************************************************************************/ + +EXTERN_C SharedObjectPtr rt_library_init(void) +{ + SharedObjectPtr library = tls_new_class<SharedObject>(); + + if (!library) + { + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); + + return nullptr; + } + + library->Mount(tls_new_class<SharedObject::SharedObjectTrait>()); + + if (!library->Get()) + { + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); + + return nullptr; + } + + library->Get()->fImageObject = + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Image; + + if (!library->Get()->fImageObject) + { + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); + + return nullptr; + } + + library->Get()->fImageEntrypointOffset = + library->Load<VoidPtr>(kPefStart, rt_string_len(kPefStart, 0), kPefCode); + + return library; +} + +/***********************************************************************************/ +/* @brief Ends the library. */ +/* @note Please check if the lib got freed! */ +/* @param SharedObjectPtr the library to free. */ +/***********************************************************************************/ + +EXTERN_C Void rt_library_free(SharedObjectPtr lib, bool* successful) +{ + MUST_PASS(successful); + + // sanity check (will also trigger a bug check if this fails) + if (lib == nullptr) + { + *successful = false; + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); + } + + delete lib->Get(); + delete lib; + + lib = nullptr; + + *successful = true; +} + +/***********************************************************************************/ + +/// @brief Unimplemented function (crashes by default) +/// @param +EXTERN_C void __mh_purecall(void) +{ + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); + return; +} diff --git a/Kernel/Source/PRDT.cxx b/Kernel/Source/PRDT.cxx new file mode 100644 index 00000000..3f454409 --- /dev/null +++ b/Kernel/Source/PRDT.cxx @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <NewKit/String.hpp> +#include <StorageKit/PRDT.hpp> + +namespace NewOS +{ + /// @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 NewOS diff --git a/Kernel/Source/PageAllocator.cxx b/Kernel/Source/PageAllocator.cxx new file mode 100644 index 00000000..bafa5a7e --- /dev/null +++ b/Kernel/Source/PageAllocator.cxx @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <KernelKit/DebugOutput.hpp> +#include <NewKit/PageAllocator.hpp> + +/// @brief Internal namespace, used internally by kernel. +namespace NewOS::Detail +{ + VoidPtr create_page_wrapper(Boolean rw, Boolean user, SizeT pageSz) + { + auto addr = HAL::hal_alloc_page(rw, user, pageSz); + + if (addr == kBadAddress) + { + kcout << "[create_page_wrapper] kBadAddress returned\n"; + ke_stop(RUNTIME_CHECK_POINTER); + } + + return addr; + } + + void exec_disable(UIntPtr VirtualAddr) + { + PTE* VirtualAddrTable = reinterpret_cast<PTE*>(VirtualAddr); + MUST_PASS(!VirtualAddrTable->Accessed); + VirtualAddrTable->ExecDisable = true; + + hal_flush_tlb(); + } + + bool page_disable(UIntPtr VirtualAddr) + { + if (VirtualAddr) + { + auto VirtualAddrTable = (PTE*)(VirtualAddr); + MUST_PASS(!VirtualAddrTable->Accessed); + + VirtualAddrTable->Present = false; + + hal_flush_tlb(); + + return true; + } + + return false; + } +} // namespace NewOS::Detail diff --git a/Kernel/Source/PageManager.cxx b/Kernel/Source/PageManager.cxx new file mode 100644 index 00000000..e1cfdeea --- /dev/null +++ b/Kernel/Source/PageManager.cxx @@ -0,0 +1,118 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <NewKit/PageManager.hpp> + +#ifdef __x86_64__ +#include <HALKit/AMD64/HalPageAlloc.hpp> +#endif // ifdef __x86_64__ + +//! null deref will throw (Page Zero detected, aborting app!) +#define kProtectedRegionEnd (512) + +namespace NewOS +{ + 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() + { + } + + /// @brief Flush virtual address. + /// @param VirtAddr + void PageManager::FlushTLB(UIntPtr VirtAddr) + { + if (VirtAddr == kBadAddress) + return; + + hal_flush_tlb(); + } + + /// @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 PageManager::Request(Boolean Rw, Boolean User, Boolean ExecDisable, SizeT Sz) + { + // Store PTE wrapper right after PTE. + VoidPtr ptr = NewOS::HAL::hal_alloc_page(Rw, User, Sz); + + return PTEWrapper{Rw, User, ExecDisable, reinterpret_cast<UIntPtr>(ptr)}; + } + + /// @brief Disable PTE. + /// @param wrapper the wrapper. + /// @return + bool PageManager::Free(Ref<PTEWrapper*>& wrapper) + { + if (wrapper) + { + if (!Detail::page_disable(wrapper->VirtualAddress())) + return false; + return true; + } + + return false; + } + + /// @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) + { + this->fExecDisable = enable; + } + + const bool& PTEWrapper::NoExecute() + { + return this->fExecDisable; + } +} // namespace NewOS diff --git a/Kernel/Source/PermissionSelector.cxx b/Kernel/Source/PermissionSelector.cxx new file mode 100644 index 00000000..cb44b237 --- /dev/null +++ b/Kernel/Source/PermissionSelector.cxx @@ -0,0 +1,47 @@ +/* + * ======================================================== + * + * NewOS + * Copyright SoftwareLabs, all rights reserved. + * + * File: PermissionSelector.cpp + * Purpose: Permission selectors. + * + * ======================================================== + */ + +#include <KernelKit/PermissionSelector.hxx> +#include <NewKit/KernelCheck.hpp> + +/// bugs 0 + +namespace NewOS +{ + PermissionSelector::PermissionSelector(const Int32& sel) + : fRing((RingKind)sel) + { + MUST_PASS(sel > 0); + } + + PermissionSelector::PermissionSelector(const RingKind& ringKind) + : fRing(ringKind) + { + } + + PermissionSelector::~PermissionSelector() = default; + + bool PermissionSelector::operator==(const PermissionSelector& lhs) + { + return lhs.fRing == this->fRing; + } + + bool PermissionSelector::operator!=(const PermissionSelector& lhs) + { + return lhs.fRing != this->fRing; + } + + const RingKind& PermissionSelector::Ring() noexcept + { + return this->fRing; + } +} // namespace NewOS diff --git a/Kernel/Source/Pmm.cxx b/Kernel/Source/Pmm.cxx new file mode 100644 index 00000000..f60f5b23 --- /dev/null +++ b/Kernel/Source/Pmm.cxx @@ -0,0 +1,85 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hpp> +#include <NewKit/Pmm.hpp> + +namespace NewOS +{ + Pmm::Pmm() + : fPageManager() + { + kcout << "[PMM] Allocate PageMemoryManager"; + } + + Pmm::~Pmm() = default; + + /* If this returns Null pointer, enter emergency mode */ + Ref<PTEWrapper> Pmm::RequestPage(Boolean user, Boolean readWrite) + { + PTEWrapper pt = fPageManager.Leak().Request(user, readWrite, false, kPTESize); + + if (pt.fPresent) + { + kcout << "[PMM]: Allocation was successful."; + return Ref<PTEWrapper>(pt); + } + + kcout << "[PMM]: Allocation failure."; + + return {}; + } + + 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 NewOS diff --git a/Kernel/Source/ProcessScheduler.cxx b/Kernel/Source/ProcessScheduler.cxx new file mode 100644 index 00000000..859ce657 --- /dev/null +++ b/Kernel/Source/ProcessScheduler.cxx @@ -0,0 +1,392 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file ProcessScheduler.cxx +/// @brief MicroKernel process scheduler. +/***********************************************************************************/ + +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/SMPManager.hpp> +#include <KernelKit/KernelHeap.hpp> +#include <NewKit/String.hpp> +#include <KernelKit/HError.hpp> + +///! BUGS: 0 + +/***********************************************************************************/ +/* This file handles the process scheduling. +/***********************************************************************************/ + +namespace NewOS +{ + /***********************************************************************************/ + /// @brief Exit Code global + /***********************************************************************************/ + + STATIC Int32 kLastExitCode = 0U; + + /// @brief Gets the latest exit code. + /// @note Not thread-safe. + const Int32& rt_get_exit_code() noexcept + { + return kLastExitCode; + } + + /***********************************************************************************/ + /// @brief crash current process. + /***********************************************************************************/ + + void ProcessHeader::Crash() + { + kcout << this->Name << ": crashed. (id = " << number(39); + kcout << ")\r"; + + if (this->Ring != kRingUserKind) + { + MUST_PASS(ke_bug_check()); + } + + this->Exit(kErrorProcessFault); + } + + void ProcessHeader::Wake(const bool should_wakeup) + { + this->Status = + should_wakeup ? ProcessStatus::kRunning : ProcessStatus::kFrozen; + } + + /***********************************************************************************/ + + VoidPtr ProcessHeader::New(const SizeT& sz) + { + if (this->FreeMemory < 1) + { + DbgLastError() = kErrorHeapOutOfMemory; + this->Crash(); /// out of memory. + + return nullptr; + } + + if (this->HeapCursor) + { + VoidPtr ptr = this->HeapCursor; + this->HeapCursor = (VoidPtr)((UIntPtr)this->HeapCursor + (sizeof(sz))); + + ++this->UsedMemory; + --this->FreeMemory; + + return ptr; + } + + return nullptr; + } + + /***********************************************************************************/ + + /* @brief checks if runtime pointer is in region. */ + bool rt_is_in_pool(VoidPtr pool_ptr, VoidPtr pool, const SizeT& sz) + { + UIntPtr* _pool_ptr = (UIntPtr*)pool_ptr; + UIntPtr* _pool = (UIntPtr*)pool; + + for (SizeT index = sz; _pool[sz] != kUserHeapMag; --index) + { + if (&_pool[index] > &_pool_ptr[sz]) + continue; + + if (_pool[index] == _pool_ptr[index]) + return true; + } + + return false; + } + + /* @brief free pointer from usage. */ + Boolean ProcessHeader::Delete(VoidPtr ptr, const SizeT& sz) + { + if (sz < 1 || this->HeapCursor == this->HeapPtr) + return false; + + // also check for the amount of allocations we've done so far. + if (this->UsedMemory < 1) + return false; + + if (rt_is_in_pool(ptr, this->HeapCursor, this->UsedMemory)) + { + this->HeapCursor = (VoidPtr)((UIntPtr)this->HeapCursor - (sizeof(sz))); + rt_zero_memory(ptr, sz); + + ++this->FreeMemory; + --this->UsedMemory; + + return true; + } + + return false; + } + + /// @brief process name getter. + const Char* ProcessHeader::GetName() + { + return this->Name; + } + + /// @brief process selector getter. + const ProcessSelector& ProcessHeader::GetSelector() + { + return this->Selector; + } + + /// @brief process status getter. + const ProcessStatus& ProcessHeader::GetStatus() + { + return this->Status; + } + + /***********************************************************************************/ + + /** +@brief Affinity is the time slot allowed for the process. +*/ + const AffinityKind& ProcessHeader::GetAffinity() + { + return this->Affinity; + } + + /** +@brief Standard exit proc. +*/ + void ProcessHeader::Exit(Int32 exit_code) + { + if (this->ProcessId != + ProcessScheduler::Shared().Leak().GetCurrent().Leak().ProcessId) + ke_stop(RUNTIME_CHECK_PROCESS); + + if (this->Ring == (Int32)ProcessSelector::kRingKernel && + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Ring > 0) + ke_stop(RUNTIME_CHECK_PROCESS); + + kLastExitCode = exit_code; + + if (this->Ring != (Int32)ProcessSelector::kRingDriver) + { + if (this->HeapPtr) + rt_free_heap(this->HeapPtr); + + this->HeapPtr = nullptr; + this->HeapCursor = nullptr; + + this->FreeMemory = 0UL; + this->UsedMemory = 0UL; + } + + //! Delete image if not done already. + if (this->Image) + ke_delete_ke_heap(this->Image); + if (this->StackFrame) + ke_delete_ke_heap((VoidPtr)this->StackFrame); + + this->Image = nullptr; + this->StackFrame = nullptr; + + ProcessScheduler::Shared().Leak().Remove(this->ProcessId); + } + + SizeT ProcessScheduler::Add(Ref<ProcessHeader>& process) + { + if (!process) + return -1; + + if (!process.Leak().Image) + { + if (process.Leak().Kind != ProcessHeader::kLibKind) + { + return -kErrorNoEntrypoint; + } + } + + if (!mTeam.AsArray().Count() > kSchedProcessLimitPerTeam) + return -kErrorOutOfTeamSlot; + + if (process.Leak().Ring != (Int32)ProcessSelector::kRingKernel) + return -1; + + kcout << "ProcessScheduler::Add(Ref<ProcessHeader>& process)\r"; + + /// Create heap according to type of process. + if (process.Leak().Kind == ProcessHeader::kUserKind) + process.Leak().HeapPtr = rt_new_heap(kUserHeapUser | kUserHeapRw); + else if (process.Leak().Kind == ProcessHeader::kLibKind) + process.Leak().HeapPtr = rt_new_heap(kUserHeapUser | kUserHeapRw | kUserHeapShared); + else + process.Leak().HeapPtr = rt_new_heap(kUserHeapDriver | kUserHeapRw); + + process.Leak().StackFrame = reinterpret_cast<HAL::StackFrame*>( + ke_new_ke_heap(sizeof(HAL::StackFrame), true, false)); + + MUST_PASS(process.Leak().StackFrame); + + mTeam.AsArray().Add(process); + + process.Leak().ProcessId = mTeam.AsArray().Count() - 1; + process.Leak().HeapCursor = process.Leak().HeapPtr; + + return mTeam.AsArray().Count() - 1; + } + + bool ProcessScheduler::Remove(SizeT process) + { + if (process > mTeam.AsArray().Count()) + return false; + + kcout << "ProcessScheduler::Remove(SizeT process)\r"; + + return mTeam.AsArray().Remove(process); + } + + SizeT ProcessScheduler::Run() noexcept + { + SizeT processIndex = 0; //! we store this guy to tell the scheduler how many + //! things we have scheduled. + + for (; processIndex < mTeam.AsArray().Count(); ++processIndex) + { + auto process = mTeam.AsArray()[processIndex]; + + MUST_PASS(process); //! no need for a MUST_PASS(process.Leak());, it is + //! recursive because of the nature of the class; + + //! run any process needed to be scheduled. + if (ProcessHelper::CanBeScheduled(process.Leak())) + { + auto unwrapped_process = *process.Leak(); + + unwrapped_process.PTime = 0; + + // set the current process. + mTeam.AsRef() = unwrapped_process; + + // tell helper to find a core to schedule on. + ProcessHelper::Switch(mTeam.AsRef().Leak().StackFrame, + mTeam.AsRef().Leak().ProcessId); + } + else + { + // otherwise increment the P-time. + ++mTeam.AsRef().Leak().PTime; + } + } + + return processIndex; + } + + Ref<ProcessScheduler> ProcessScheduler::Shared() + { + static ProcessScheduler ref; + return {ref}; + } + + /// @brief Gets current running process. + /// @return + Ref<ProcessHeader>& ProcessScheduler::GetCurrent() + { + return mTeam.AsRef(); + } + + PID& ProcessHelper::GetCurrentPID() + { + kcout << "ProcessHelper::GetCurrentPID: Leaking ProcessId...\r"; + return ProcessScheduler::Shared().Leak().GetCurrent().Leak().ProcessId; + } + + bool ProcessHelper::CanBeScheduled(Ref<ProcessHeader>& process) + { + if (process.Leak().Status == ProcessStatus::kFrozen || + process.Leak().Status == ProcessStatus::kDead) + return false; + + if (process.Leak().GetStatus() == ProcessStatus::kStarting) + { + if (process.Leak().PTime < static_cast<Int>(kSchedMinMicroTime)) + { + process.Leak().Status = ProcessStatus::kRunning; + process.Leak().Affinity = AffinityKind::kHartStandard; + + return true; + } + + ++process.Leak().PTime; + } + + return process.Leak().PTime > static_cast<Int>(kSchedMinMicroTime); + } + + /** + * @brief Spin scheduler class. + */ + bool ProcessHelper::StartScheduling() + { + if (ProcessHelper::CanBeScheduled( + ProcessScheduler::Shared().Leak().GetCurrent())) + { + --ProcessScheduler::Shared().Leak().GetCurrent().Leak().PTime; + return false; + } + + auto processRef = ProcessScheduler::Shared().Leak(); + + if (!processRef) + return false; // we have nothing to schedule. simply return. + + SizeT ret = processRef.Run(); + + kcout << StringBuilder::FromInt( + "ProcessHelper::StartScheduling() Iterated over {%} jobs inside team.\r", ret); + + return true; + } + + /** + * \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 ProcessHelper::Switch(HAL::StackFrame* the_stack, const PID& new_pid) + { + if (!the_stack || new_pid < 0) + return false; + + for (SizeT index = 0UL; index < SMPManager::Shared().Leak().Count(); ++index) + { + if (SMPManager::Shared().Leak()[index].Leak().Kind() == kInvalidHart) + continue; + + if (SMPManager::Shared().Leak()[index].Leak().StackFrame() == the_stack) + { + SMPManager::Shared().Leak()[index].Leak().Busy(false); + continue; + } + + if (SMPManager::Shared().Leak()[index].Leak().IsBusy()) + continue; + + if (SMPManager::Shared().Leak()[index].Leak().Kind() != + ThreadKind::kHartBoot && + SMPManager::Shared().Leak()[index].Leak().Kind() != + ThreadKind::kHartSystemReserved) + { + SMPManager::Shared().Leak()[index].Leak().Busy(true); + ProcessHelper::GetCurrentPID() = new_pid; + + return SMPManager::Shared().Leak()[index].Leak().Switch(the_stack); + } + } + + return false; + } +} // namespace NewOS diff --git a/Kernel/Source/ProcessTeam.cxx b/Kernel/Source/ProcessTeam.cxx new file mode 100644 index 00000000..959402f4 --- /dev/null +++ b/Kernel/Source/ProcessTeam.cxx @@ -0,0 +1,31 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file ProcessTeam.cxx +/// @brief Process teams implementation. +/***********************************************************************************/ + +#include <KernelKit/ProcessScheduler.hpp> + +namespace NewOS +{ + /// @brief Process list array getter. + /// @return The list of process to schedule. + MutableArray<Ref<ProcessHeader>>& ProcessTeam::AsArray() + { + return mProcessList; + } + + /// @brief Current process getter. + /// @return The current process header. + Ref<ProcessHeader>& ProcessTeam::AsRef() + { + return mCurrentProcess; + } +} // namespace NewOS + +// last rev 05-03-24 diff --git a/Kernel/Source/Property.cxx b/Kernel/Source/Property.cxx new file mode 100644 index 00000000..ab4f7bf5 --- /dev/null +++ b/Kernel/Source/Property.cxx @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <CFKit/Property.hpp> + +namespace NewOS +{ + bool Property::StringEquals(StringView& name) + { + return fName && this->fName == name; + } + + const PropertyId& Property::GetPropertyById() + { + return fAction; + } +} // namespace NewOS diff --git a/Kernel/Source/Ref.cxx b/Kernel/Source/Ref.cxx new file mode 100644 index 00000000..60f02b69 --- /dev/null +++ b/Kernel/Source/Ref.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Ref.hpp> diff --git a/Kernel/Source/SMPManager.cxx b/Kernel/Source/SMPManager.cxx new file mode 100644 index 00000000..d9aac48e --- /dev/null +++ b/Kernel/Source/SMPManager.cxx @@ -0,0 +1,217 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/SMPManager.hpp> + +///! BUGS: 0 + +///! @file SMPManager.cxx +///! @brief This file handles multi processing in NewOS. +///! @brief Multi processing is needed for multi-tasking operations. + +namespace NewOS +{ + ///! A HardwareThread class takes care of it's owned hardware thread. + ///! It has a stack for it's core. + + ///! @brief constructor + HardwareThread::HardwareThread() = default; + + ///! @brief destructor + HardwareThread::~HardwareThread() = default; + + //! @brief returns the id + + const ThreadID& HardwareThread::ID() noexcept + { + return fID; + } + + //! @brief returns the kind + + const ThreadKind& HardwareThread::Kind() noexcept + { + return fKind; + } + + //! @brief is the core busy? + + bool HardwareThread::IsBusy() noexcept + { + return fBusy; + } + + /// @brief Get processor stack frame. + + HAL::StackFramePtr HardwareThread::StackFrame() noexcept + { + MUST_PASS(fStack); + return fStack; + } + + void HardwareThread::Busy(const bool busy) noexcept + { + fBusy = busy; + } + + HardwareThread::operator bool() + { + return fStack; + } + + /// @brief Wakeup the processor. + + void HardwareThread::Wake(const bool wakeup) noexcept + { + fWakeup = wakeup; + + if (!fWakeup) + rt_hang_thread(fStack); + else + rt_wakeup_thread(fStack); + } + + extern bool rt_check_stack(HAL::StackFramePtr stackPtr); + + bool HardwareThread::Switch(HAL::StackFramePtr stack) + { + if (!rt_check_stack(stack)) + return false; + + fStack = stack; + + rt_do_context_switch(fStack); + return true; + } + + ///! @brief Tells if processor is waked up. + bool HardwareThread::IsWakeup() noexcept + { + return fWakeup; + } + + //! @brief Constructor and destructor + + ///! @brief Default constructor. + SMPManager::SMPManager() = default; + + ///! @brief Default destructor. + SMPManager::~SMPManager() = default; + + /// @brief Shared singleton function + Ref<SMPManager> SMPManager::Shared() + { + static SMPManager manager; + return {manager}; + } + + /// @brief Get Stack Frame of Core + HAL::StackFramePtr SMPManager::GetStackFrame() noexcept + { + if (fThreadList[fCurrentThread].Leak() && + ProcessHelper::GetCurrentPID() == + fThreadList[fCurrentThread].Leak().Leak().fPID) + return fThreadList[fCurrentThread].Leak().Leak().fStack; + + return nullptr; + } + + /// @brief Finds and switch to a free core. + bool SMPManager::Switch(HAL::StackFramePtr stack) + { + if (stack == nullptr) + return false; + + for (SizeT idx = 0; idx < kMaxHarts; ++idx) + { + // stack != nullptr -> if core is used, then continue. + if (!fThreadList[idx].Leak() || + !fThreadList[idx].Leak().Leak().IsWakeup() || + fThreadList[idx].Leak().Leak().IsBusy()) + continue; + + // to avoid any null deref. + if (!fThreadList[idx].Leak().Leak().fStack) + continue; + if (fThreadList[idx].Leak().Leak().fStack->Rsp == 0) + continue; + if (fThreadList[idx].Leak().Leak().fStack->Rbp == 0) + continue; + + fThreadList[idx].Leak().Leak().Busy(true); + + fThreadList[idx].Leak().Leak().fID = idx; + + /// I figured out this: + /// Allocate stack + /// Set APIC base to stack + /// Do stuff and relocate stack based on this code. + /// - Amlel + rt_copy_memory(stack, fThreadList[idx].Leak().Leak().fStack, + sizeof(HAL::StackFrame)); + + fThreadList[idx].Leak().Leak().fPID = ProcessHelper::GetCurrentPID(); + + fThreadList[idx].Leak().Leak().Busy(false); + + return true; + } + + return false; + } + + /** + * Index Hardware thread + * @param idx the index + * @return the reference to the hardware thread. + */ + Ref<HardwareThread> SMPManager::operator[](const SizeT& idx) + { + if (idx == 0) + { + if (fThreadList[idx].Leak().Leak().Kind() != kHartSystemReserved) + { + fThreadList[idx].Leak().Leak().fKind = kHartBoot; + } + } + else if (idx >= kMaxHarts) + { + HardwareThread fakeThread; + fakeThread.fKind = kInvalidHart; + + return {fakeThread}; + } + + return fThreadList[idx].Leak(); + } + + /** + * Check if thread pool isn't empty. + * @return + */ + SMPManager::operator bool() noexcept + { + return !fThreadList.Empty(); + } + + /** + * Reverse operator bool + * @return + */ + bool SMPManager::operator!() noexcept + { + return fThreadList.Empty(); + } + + /// @brief Returns the amount of core present. + /// @return the number of cores. + SizeT SMPManager::Count() noexcept + { + return fThreadList.Count(); + } +} // namespace NewOS diff --git a/Kernel/Source/Semaphore.cxx b/Kernel/Source/Semaphore.cxx new file mode 100644 index 00000000..eebdd210 --- /dev/null +++ b/Kernel/Source/Semaphore.cxx @@ -0,0 +1,53 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/Semaphore.hpp> +#include <KernelKit/Timer.hpp> + +namespace NewOS +{ + bool Semaphore::Unlock() noexcept + { + if (fLockingProcess) + fLockingProcess = nullptr; + + return fLockingProcess == nullptr; + } + + bool Semaphore::Lock(ProcessHeader* process) + { + if (!process || fLockingProcess) + return false; + + fLockingProcess = process; + + return true; + } + + bool Semaphore::IsLocked() const + { + return fLockingProcess; + } + + bool Semaphore::LockOrWait(ProcessHeader* process, const Int64& seconds) + { + if (process == nullptr) + return false; + + HardwareTimer timer(Seconds(seconds)); + timer.Wait(); + + return this->Lock(process); + } + + void Semaphore::Sync() noexcept + { + while (fLockingProcess) + { + } + } +} // namespace NewOS diff --git a/Kernel/Source/Storage/AHCIDeviceInterface.cxx b/Kernel/Source/Storage/AHCIDeviceInterface.cxx new file mode 100644 index 00000000..da25c05d --- /dev/null +++ b/Kernel/Source/Storage/AHCIDeviceInterface.cxx @@ -0,0 +1,35 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <StorageKit/AHCI.hpp> + +using namespace NewOS; + +/// @brief Class constructor +/// @param Out Disk output +/// @param In Disk input +/// @param Cleanup Disk cleanup. +AHCIDeviceInterface::AHCIDeviceInterface(void (*Out)(MountpointInterface* outpacket), + void (*In)(MountpointInterface* inpacket), + void (*Cleanup)(void)) + : DeviceInterface(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 "AHCIDeviceInterface"; +} diff --git a/Kernel/Source/Storage/ATADeviceInterface.cxx b/Kernel/Source/Storage/ATADeviceInterface.cxx new file mode 100644 index 00000000..5624dddb --- /dev/null +++ b/Kernel/Source/Storage/ATADeviceInterface.cxx @@ -0,0 +1,88 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <StorageKit/ATA.hpp> + +using namespace NewOS; + +/// @brief Class constructor +/// @param Out Disk output +/// @param In Disk input +/// @param Cleanup Disk cleanup. +ATADeviceInterface::ATADeviceInterface( + void (*Out)(MountpointInterface* outpacket), + void (*In)(MountpointInterface* inpacket), + void (*Cleanup)(void)) + : DeviceInterface(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 "ATADeviceInterface"; +} + +/// @brief Output operator. +/// @param Data +/// @return +ATADeviceInterface& ATADeviceInterface::operator<<(MountpointInterface* Data) +{ + if (!Data) + return *this; + + for (SizeT driveCount = 0; driveCount < kDriveManagerCount; ++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&)DeviceInterface<MountpointInterface*>::operator<<( + Data); +} + +/// @brief Input operator. +/// @param Data +/// @return +ATADeviceInterface& ATADeviceInterface::operator>>(MountpointInterface* Data) +{ + if (!Data) + return *this; + + for (SizeT driveCount = 0; driveCount < kDriveManagerCount; ++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&)DeviceInterface<MountpointInterface*>::operator>>( + Data); +} diff --git a/Kernel/Source/Storage/NVMEDeviceInterface.cxx b/Kernel/Source/Storage/NVMEDeviceInterface.cxx new file mode 100644 index 00000000..aaaa3eb0 --- /dev/null +++ b/Kernel/Source/Storage/NVMEDeviceInterface.cxx @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <StorageKit/NVME.hpp> + +namespace NewOS +{ + const char* NVMEDeviceInterface::Name() const + { + return ("NVMEDeviceInterface"); + } +} // namespace NewOS diff --git a/Kernel/Source/Storage/SCSIDeviceInterface.cxx b/Kernel/Source/Storage/SCSIDeviceInterface.cxx new file mode 100644 index 00000000..16105547 --- /dev/null +++ b/Kernel/Source/Storage/SCSIDeviceInterface.cxx @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <StorageKit/SCSI.hxx> + +///! @brief ATAPI SCSI packet. +const scsi_packet_type kCDRomPacketTemplate = {0x43, 0, 1, 0, 0, 0, + 0, 12, 0x40, 0, 0}; diff --git a/Kernel/Source/Stream.cxx b/Kernel/Source/Stream.cxx new file mode 100644 index 00000000..134ec586 --- /dev/null +++ b/Kernel/Source/Stream.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: Stream.cxx + Purpose: Stream object + + Revision History: + +------------------------------------------- */ + +#include <NewKit/Stream.hpp> diff --git a/Kernel/Source/String.cxx b/Kernel/Source/String.cxx new file mode 100644 index 00000000..764ab0d9 --- /dev/null +++ b/Kernel/Source/String.cxx @@ -0,0 +1,248 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/String.hpp> +#include <NewKit/Utils.hpp> +#include <KernelKit/DebugOutput.hpp> + +namespace NewOS +{ + Char* StringView::Data() + { + return fData; + } + + const Char* StringView::CData() + { + return fData; + } + + Size StringView::Length() const + { + return rt_string_len(fData); + } + + bool StringView::operator==(const StringView& rhs) const + { + if (rhs.Length() != this->Length()) + return false; + + for (Size index = 0; index < this->Length(); ++index) + { + if (rhs.fData[index] != fData[index]) + return false; + } + + return true; + } + + bool StringView::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] != fData[index]) + return false; + } + + return true; + } + + bool StringView::operator!=(const StringView& rhs) const + { + if (rhs.Length() != this->Length()) + return false; + + for (Size index = 0; index < rhs.Length(); ++index) + { + if (rhs.fData[index] == fData[index]) + return false; + } + + return true; + } + + bool StringView::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] == fData[index]) + return false; + } + + return true; + } + + ErrorOr<StringView> StringBuilder::Construct(const Char* data) + { + if (!data || *data == 0) + return {}; + + StringView view(rt_string_len(data)); + + view += data; + + return ErrorOr<StringView>(view); + } + + const char* StringBuilder::FromInt(const char* fmt, int i) + { + if (!fmt) + return ("-1"); + + char* ret = (char*)Alloca(sizeof(char) * 8 + rt_string_len(fmt)); + + if (!ret) + return ("-1"); + + Char result[8]; + + if (!rt_to_string(result, sizeof(int), i)) + { + return ("-1"); + } + + const auto fmt_len = rt_string_len(fmt); + const auto res_len = rt_string_len(result); + + 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] = result[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ + } + + const char* StringBuilder::FromBool(const char* fmt, bool i) + { + if (!fmt) + return ("?"); + + const char* boolean_expr = i ? "true" : "false"; + char* ret = (char*)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 StringBuilder::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; + } + + const char* StringBuilder::Format(const char* fmt, const char* fmt2) + { + if (!fmt || !fmt2) + return ("?"); + + char* ret = + (char*)Alloca(sizeof(char) * rt_string_len(fmt2) + rt_string_len(fmt2)); + + if (!ret) + return ("?"); + + for (Size idx = 0; idx < rt_string_len(fmt); ++idx) + { + if (fmt[idx] == '%') + { + 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; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; + } + + static void string_append(char* lhs, char* rhs, int cur) + { + if (lhs && rhs) + { + SizeT sz_rhs = rt_string_len(rhs); + + if (sz_rhs == 0) + return; + + rt_copy_memory(rhs, lhs + cur, sz_rhs); + } + } + + StringView& StringView::operator+=(const Char* rhs) + { + string_append(this->fData, const_cast<char*>(rhs), this->fCur); + this->fCur += rt_string_len(rhs); + + return *this; + } + + StringView& StringView::operator+=(const StringView& rhs) + { + if (rt_string_len(rhs.fData) > rt_string_len(this->fData)) + return *this; + + string_append(this->fData, const_cast<char*>(rhs.fData), this->fCur); + this->fCur += rt_string_len(const_cast<char*>(rhs.fData)); + + return *this; + } +} // namespace NewOS diff --git a/Kernel/Source/ThreadLocalStorage.cxx b/Kernel/Source/ThreadLocalStorage.cxx new file mode 100644 index 00000000..c31ae1c2 --- /dev/null +++ b/Kernel/Source/ThreadLocalStorage.cxx @@ -0,0 +1,58 @@ +/* + * ======================================================== + * + * NewOS + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/ThreadLocalStorage.hxx> + +///! BUGS: 0 + +/***********************************************************************************/ +/// @file ThreadLocalStorage.cxx +/// @brief TLS implementation in kernel. +/***********************************************************************************/ + +using namespace NewOS; + +/** + * @brief Check for cookie inside TIB. + * @param tib the TIB to check. + * @return if the cookie is enabled. + */ + +Boolean tls_check_tib(ThreadInformationBlock* tib) +{ + if (!tib) + return false; + + Encoder encoder; + const char* tibAsBytes = encoder.AsBytes(tib); + + kcout << "New OS: Checking for a valid cookie...\r"; + + return tibAsBytes[0] == kCookieMag0 && tibAsBytes[1] == kCookieMag1 && + tibAsBytes[2] == kCookieMag2; +} + +/** + * @brief System call implementation of the TLS check. + * @param stackPtr The call frame. + * @return + */ +EXTERN_C Void tls_check_syscall_impl(NewOS::HAL::StackFramePtr stackPtr) noexcept +{ + ThreadInformationBlock* tib = (ThreadInformationBlock*)stackPtr->Gs; + + if (!tls_check_tib(tib)) + { + kcout << "New OS: Verification failed, Crashing...\r"; + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); + } + + kcout << "New OS: Verification succeeded! Keeping on...\r"; +} diff --git a/Kernel/Source/Timer.cxx b/Kernel/Source/Timer.cxx new file mode 100644 index 00000000..3e705c38 --- /dev/null +++ b/Kernel/Source/Timer.cxx @@ -0,0 +1,41 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/Timer.hpp> + +///! BUGS: 0 +///! @file Timer.cxx + +using namespace NewOS; + +/// @brief Unimplemented as it is an interface. +Int32 HardwareTimerInterface::Wait() noexcept +{ + return kErrorUnimplemented; +} + +/// @brief HardwareTimer class, meant to be generic. + +HardwareTimer::HardwareTimer(Int64 seconds) + : fWaitFor(seconds) +{ +} +HardwareTimer::~HardwareTimer() +{ + fWaitFor = 0; +} + +Int32 HardwareTimer::Wait() noexcept +{ + if (fWaitFor < 1) + return -1; + + while (*fDigitalTimer < (*fDigitalTimer + fWaitFor)) + { + } + + return 0; +} diff --git a/Kernel/Source/URL.cxx b/Kernel/Source/URL.cxx new file mode 100644 index 00000000..8c11ca55 --- /dev/null +++ b/Kernel/Source/URL.cxx @@ -0,0 +1,96 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <CFKit/URL.hpp> +#include <KernelKit/DebugOutput.hpp> +#include <NewKit/Utils.hpp> + +/// BUGS: 0 + +namespace NewOS +{ + URL::URL(StringView& strUrl) + : fUrlView(strUrl, false) + { + } + + URL::~URL() = default; + + /// @brief internal and reserved protocols by kernel. + constexpr const char* kURLProtocols[] = { + "file", // Filesystem protocol + "mup", // Mahrouss update protocol + "param", // Mahrouss parameter protocol. + }; + + constexpr const int kUrlOutSz = 1; //! such as: :// + constexpr const int kProtosCount = 3; + constexpr const int kRangeSz = 4096; + + ErrorOr<StringView> url_extract_location(const char* url) + { + if (!url || *url == 0 || rt_string_len(url, kRangeSz) > kRangeSz) + return ErrorOr<StringView>{-1}; + + StringView view(rt_string_len(url)); + + SizeT i = 0; + bool scheme_found = false; + + for (; i < rt_string_len(url); ++i) + { + if (!scheme_found) + { + for (int y = 0; kProtosCount; ++y) + { + if (rt_string_in_string(view.CData(), kURLProtocols[y])) + { + i += rt_string_len(kURLProtocols[y]) + kUrlOutSz; + scheme_found = true; + + break; + } + } + } + + view.Data()[i] = url[i]; + } + + return ErrorOr<StringView>(view); + } + + ErrorOr<StringView> url_extract_protocol(const char* url) + { + if (!url || *url == 0 || rt_string_len(url, kRangeSz) > kRangeSz) + return ErrorOr<StringView>{-1}; + + ErrorOr<StringView> view{-1}; + + return view; + } + + Ref<ErrorOr<StringView>> URL::Location() noexcept + { + const char* src = fUrlView.Leak().CData(); + auto loc = url_extract_location(src); + + if (!loc) + return {}; + + return Ref<ErrorOr<StringView>>(loc); + } + + Ref<ErrorOr<StringView>> URL::Protocol() noexcept + { + const char* src = fUrlView.Leak().CData(); + auto loc = url_extract_protocol(src); + + if (!loc) + return {}; + + return Ref<ErrorOr<StringView>>(loc); + } +} // namespace NewOS diff --git a/Kernel/Source/UserHeap.cxx b/Kernel/Source/UserHeap.cxx new file mode 100644 index 00000000..9d9cd627 --- /dev/null +++ b/Kernel/Source/UserHeap.cxx @@ -0,0 +1,252 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/UserHeap.hpp> +#include <NewKit/PageManager.hpp> + +#define kHeapHeaderPaddingSz (16U) + +/// @file UserHeap.cxx +/// @brief User Heap Manager, Process heap allocator. +/// @note if you want to look at the kernel allocator, please look for +/// KernelHeap.cxx +/// BUGS: 0 + +namespace NewOS +{ + /** + * @brief Process Heap Header + * @note Allocated per process, it denotes the user's heap. + */ + struct UserHeapHeader final + { + UInt32 fMagic; + Int32 fFlags; + Boolean fFree; + UInt8 fPadding[kHeapHeaderPaddingSz]; + }; + + /** + * @brief User Heap Manager class, takes care of allocating the process pools. + * @note This rely on Virtual Memory! Consider adding good vmem support when + * @note porting to a new arch. + */ + class UserHeapManager final + { + public: + UserHeapManager() = delete; + ~UserHeapManager() = default; + + public: + STATIC SizeT& Count() + { + return s_NumPools; + } + STATIC Ref<Pmm>& Leak() + { + return s_Pmm; + } + STATIC Boolean& IsEnabled() + { + return s_PoolsAreEnabled; + } + STATIC MutableArray<Ref<PTEWrapper>>& The() + { + return s_Pool; + } + + private: + STATIC Size s_NumPools; + STATIC Ref<Pmm> s_Pmm; + + private: + STATIC Boolean s_PoolsAreEnabled; + STATIC MutableArray<Ref<PTEWrapper>> s_Pool; + }; + + //! declare fields + + SizeT UserHeapManager::s_NumPools = 0UL; + Ref<Pmm> UserHeapManager::s_Pmm; + Boolean UserHeapManager::s_PoolsAreEnabled = true; + MutableArray<Ref<PTEWrapper>> UserHeapManager::s_Pool; + + STATIC VoidPtr ke_find_unused_heap(Int32 flags); + STATIC Void ke_free_heap_internal(VoidPtr vaddr); + STATIC VoidPtr ke_make_heap_internal(VoidPtr vaddr, Int32 flags); + STATIC Boolean ke_check_and_free_heap(const SizeT& index, VoidPtr ptr); + + /// @brief Find an unused heap header to allocate on. + /// @param flags the flags to use. + /// @return VoidPtr the heap pointer. + STATIC VoidPtr ke_find_unused_heap(Int32 flags) + { + for (SizeT index = 0; index < kUserHeapMaxSz; ++index) + { + if (UserHeapManager::The()[index] && + !UserHeapManager::The()[index].Leak().Leak().Present()) + { + UserHeapManager::Leak().Leak().TogglePresent( + UserHeapManager::The()[index].Leak().Leak(), true); + kcout << "[ke_find_unused_heap] Done, trying to make a pool now...\r"; + + return ke_make_heap_internal( + (VoidPtr)UserHeapManager::The()[index].Leak().Leak().VirtualAddress(), + flags); + } + } + + return nullptr; + } + + /// @brief Makes a new heap for the process to use. + /// @param virtualAddress the virtual address of the process. + /// @param flags the flags. + /// @return + STATIC VoidPtr ke_make_heap_internal(VoidPtr virtualAddress, Int32 flags) + { + if (virtualAddress) + { + UserHeapHeader* poolHdr = reinterpret_cast<UserHeapHeader*>(virtualAddress); + + if (!poolHdr->fFree) + { + kcout + << "[ke_make_heap_internal] poolHdr->fFree, HeapPtr already exists\n"; + return nullptr; + } + + poolHdr->fFlags = flags; + poolHdr->fMagic = kUserHeapMag; + poolHdr->fFree = false; + + kcout << "[ke_make_heap_internal] New allocation has been done.\n"; + return reinterpret_cast<VoidPtr>( + (reinterpret_cast<UIntPtr>(virtualAddress) + sizeof(UserHeapHeader))); + } + + kcout << "[ke_make_heap_internal] Address is invalid"; + return nullptr; + } + + /// @brief Internally makrs the heap as free. + /// This is done by setting the fFree bit to true + /// @param virtualAddress + /// @return + STATIC Void ke_free_heap_internal(VoidPtr virtualAddress) + { + UserHeapHeader* poolHdr = reinterpret_cast<UserHeapHeader*>( + reinterpret_cast<UIntPtr>(virtualAddress) - sizeof(UserHeapHeader)); + + if (poolHdr->fMagic == kUserHeapMag) + { + if (!poolHdr->fFree) + { + ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); + return; + } + + poolHdr->fFree = true; + poolHdr->fFlags = 0; + + kcout << "[ke_free_heap_internal] Successfully marked header as free!\r"; + } + } + + /** + * @brief Check for the ptr and frees it. + * + * @param index Where to look at. + * @param ptr The ptr to check. + * @return Boolean true if successful. + */ + STATIC Boolean ke_check_and_free_heap(const SizeT& index, VoidPtr ptr) + { + if (UserHeapManager::The()[index]) + { + // ErrorOr<>::operator Boolean + /// if (address matches) + /// -> Free heap. + if (UserHeapManager::The()[index].Leak().Leak().VirtualAddress() == + (UIntPtr)ptr) + { + UserHeapManager::Leak().Leak().FreePage( + UserHeapManager::The()[index].Leak().Leak()); + + --UserHeapManager::Count(); + + ke_free_heap_internal(ptr); + ptr = nullptr; + + return true; + } + } + + return false; + } + + /// @brief Creates a new pool pointer. + /// @param flags the flags attached to it. + /// @return a pool pointer with selected permissions. + VoidPtr rt_new_heap(Int32 flags) + { + if (!UserHeapManager::IsEnabled()) + return nullptr; + + if (UserHeapManager::Count() > kUserHeapMaxSz) + return nullptr; + + if (VoidPtr ret = ke_find_unused_heap(flags)) + return ret; + + // this wasn't set to true + auto ref_page = UserHeapManager::Leak().Leak().RequestPage( + ((flags & kUserHeapUser)), (flags & kUserHeapRw)); + + if (ref_page) + { + ///! reserve page. + UserHeapManager::The()[UserHeapManager::Count()].Leak() = ref_page; + auto& ref = UserHeapManager::Count(); + + ++ref; // increment the number of addresses we have now. + + // finally make the pool address. + return ke_make_heap_internal( + reinterpret_cast<VoidPtr>(ref_page.Leak().VirtualAddress()), flags); + } + + return nullptr; + } + + /// @brief free a pool pointer. + /// @param ptr The pool pointer to free. + /// @return status code + Int32 rt_free_heap(VoidPtr ptr) + { + if (!UserHeapManager::IsEnabled()) + return -1; + + if (ptr) + { + SizeT base = UserHeapManager::Count(); + + if (ke_check_and_free_heap(base, ptr)) + return 0; + + for (SizeT index = 0; index < kUserHeapMaxSz; ++index) + { + if (ke_check_and_free_heap(index, ptr)) + return 0; + + --base; + } + } + + return -1; + } +} // namespace NewOS diff --git a/Kernel/Source/Utils.cxx b/Kernel/Source/Utils.cxx new file mode 100644 index 00000000..f621594d --- /dev/null +++ b/Kernel/Source/Utils.cxx @@ -0,0 +1,253 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Utils.hpp> +#include <KernelKit/DebugOutput.hpp> +#include <cstddef> + +namespace NewOS +{ + Int 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); + } + + Size rt_string_len(const Char* str, SizeT _len) + { + if (*str == '\0') + return 0; + + Size len{0}; + while (str[len] != '\0') + { + if (len > _len) + { + break; + } + + ++len; + } + + return len; + } + + Size rt_string_len(const Char* ptr) + { + if (!ptr) + return 0; + + SizeT cnt = 0; + + while (*ptr != (Char)0) + { + ++ptr; + ++cnt; + } + + return cnt; + } + + voidPtr rt_set_memory(voidPtr src, char value, Size len) + { + if (!src || len < 1) + return nullptr; + char* start = reinterpret_cast<Char*>(src); + + while (len) + { + *start = value; + ++start; + --len; + } + + return (voidPtr)start; + } + + Int rt_move_memory(const voidPtr src, voidPtr dst, Size len) + { + if (len < 1) + return -2; + if (!src || !dst) + return -1; + + char* srcChr = reinterpret_cast<Char*>(src); + char* dstChar = reinterpret_cast<Char*>(dst); + Size 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) + { + if (len < 1) + return -2; + + char* srcChr = reinterpret_cast<char*>(src); + char* dstChar = reinterpret_cast<char*>(dst); + Size index = 0; + + while (index < len) + { + dstChar[index] = srcChr[index]; + ++index; + } + + return index; + } + + const Char* alloc_string(const Char* text) + { + if (!text) + return nullptr; + + const Char* string = new Char[rt_string_len(text)]; + if (!string) + return nullptr; + + voidPtr vText = reinterpret_cast<voidPtr>(const_cast<char*>(text)); + voidPtr vStr = reinterpret_cast<voidPtr>(const_cast<char*>(string)); + rt_copy_memory(vText, vStr, rt_string_len(text)); + + return string; + } + + Int rt_to_uppercase(Int character) + { + if (character >= 'a' && character <= 'z') + return character - 0x20; + + return character; + } + + Int rt_to_lower(Int character) + { + if (character >= 'A' && character <= 'Z') + return character + 0x20; + + return character; + } + + bool rt_to_string(Char* str, Int limit, Int base) + { + if (limit == 0) + return false; + + Int copy_limit = limit; + Int cnt = 0; + Int ret = base; + + while (limit != 1) + { + ret = ret % 10; + str[cnt] = ret; + + ++cnt; + --limit; + --ret; + } + + str[copy_limit] = '\0'; + return true; + } + + Boolean is_space(Char chr) + { + return chr == ' '; + } + + Boolean is_newln(Char chr) + { + return chr == '\n'; + } + + voidPtr rt_string_in_string(const char* in, const char* needle) + { + for (size_t 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; + } + + // @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 NewOS + +//////////////////////////////////////////////////////////////////////////////////////// +/// Exported C functions +//////////////////////////////////////////////////////////////////////////////////////// + +/// @brief memset in C++ +EXTERN_C void memset(void* dst, char src, size_t len) +{ + NewOS::rt_set_memory(dst, src, len); +} + +/// @brief memcpy in C++ +EXTERN_C void memcpy(void* dst, void* src, size_t len) +{ + NewOS::rt_copy_memory(src, dst, len); +} + +/// @brief memmove in C++ +EXTERN_C void* memmove(void* dst, void* src, size_t len) +{ + NewOS::rt_copy_memory(src, dst, len); + return dst; +} + +/// @brief strlen definition in C++. +EXTERN_C size_t strlen(const char* whatToCheck) +{ + return NewOS::rt_string_len(whatToCheck); +} + +/// @brief memcmp in C++ +EXTERN_C NewOS::SizeT memcmp(void* dst, void* src, size_t len) +{ + return NewOS::rt_string_cmp((char*)src, (char*)dst, len); +} + +/// @brief strcmp in C++ +EXTERN_C NewOS::SizeT strcmp(char* dst, char* src, size_t len) +{ + return NewOS::rt_string_cmp(src, dst, len); +} diff --git a/Kernel/Source/Variant.cxx b/Kernel/Source/Variant.cxx new file mode 100644 index 00000000..afe66624 --- /dev/null +++ b/Kernel/Source/Variant.cxx @@ -0,0 +1,29 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <NewKit/Variant.hpp> + +namespace NewOS +{ + const Char* Variant::ToString() + { + if (fPtr == nullptr) + { + return ("Memory:{Nullptr}"); + } + + switch (fKind) + { + case VariantKind::kString: + return ("Class:{String}"); + case VariantKind::kPointer: + return ("Memory:{Pointer}"); + default: + return ("Memory:{Undefined}"); + } + } + +} // namespace NewOS diff --git a/Kernel/Source/compile_flags.txt b/Kernel/Source/compile_flags.txt new file mode 100644 index 00000000..1f54e6fb --- /dev/null +++ b/Kernel/Source/compile_flags.txt @@ -0,0 +1,7 @@ +-nostdlib +-ffreestanding +-std=c++20 +-I../ +-I$(HOME)/ +-D__FSKIT_NEWFS__ +-D__NEWOS_AMD64__ |
