diff options
| author | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2024-08-18 21:39:29 +0200 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2024-08-18 21:39:29 +0200 |
| commit | da70596895d8135e08f8caac6978117697b4c021 (patch) | |
| tree | 2516785b5434df8453687f05dc8dd877438901ab /dev/ZKA/Sources | |
| parent | 005de79004c9d30e64bdee6e14e06f9d47d1f2ab (diff) | |
[REFACTOR]
Improved project structure.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'dev/ZKA/Sources')
59 files changed, 5896 insertions, 0 deletions
diff --git a/dev/ZKA/Sources/Array.cxx b/dev/ZKA/Sources/Array.cxx new file mode 100644 index 00000000..202bee7e --- /dev/null +++ b/dev/ZKA/Sources/Array.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Array.hxx> diff --git a/dev/ZKA/Sources/ArrayList.cxx b/dev/ZKA/Sources/ArrayList.cxx new file mode 100644 index 00000000..71589c9b --- /dev/null +++ b/dev/ZKA/Sources/ArrayList.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/ArrayList.hxx> diff --git a/dev/ZKA/Sources/Atom.cxx b/dev/ZKA/Sources/Atom.cxx new file mode 100644 index 00000000..e5a3f407 --- /dev/null +++ b/dev/ZKA/Sources/Atom.cxx @@ -0,0 +1,10 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Atom.hxx> + +// @file Atom.cpp +// @brief Atomic primitives diff --git a/dev/ZKA/Sources/CodeManager.cxx b/dev/ZKA/Sources/CodeManager.cxx new file mode 100644 index 00000000..c0d1d308 --- /dev/null +++ b/dev/ZKA/Sources/CodeManager.cxx @@ -0,0 +1,30 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Utils.hxx> +#include <KernelKit/CodeManager.hxx> +#include <KernelKit/ProcessScheduler.hxx> + +namespace Kernel +{ + /// @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; + + PROCESS_HEADER_BLOCK proc((VoidPtr)main); + proc.Kind = PROCESS_HEADER_BLOCK::kAppKind; + rt_copy_memory((VoidPtr)processName, proc.Name, rt_string_len(proc.Name)); + + Ref<PROCESS_HEADER_BLOCK> refProc = proc; + + return ProcessScheduler::The().Leak().Add(refProc); + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/Crc32.cxx b/dev/ZKA/Sources/Crc32.cxx new file mode 100644 index 00000000..42dc9b8e --- /dev/null +++ b/dev/ZKA/Sources/Crc32.cxx @@ -0,0 +1,74 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Crc32.hxx> + +// @file CRC32.cpp +// @brief Check sequence implementation. + +namespace Kernel +{ + /// @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 Kernel diff --git a/dev/ZKA/Sources/CxxAbi-AMD64.cxx b/dev/ZKA/Sources/CxxAbi-AMD64.cxx new file mode 100644 index 00000000..5514336e --- /dev/null +++ b/dev/ZKA/Sources/CxxAbi-AMD64.cxx @@ -0,0 +1,91 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#ifdef __NEWOS_AMD64__ + +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/CxxAbi.hxx> +#include <KernelKit/LPC.hxx> + +atexit_func_entry_t __atexit_funcs[kDSOMaxObjects]; + +uarch_t __atexit_func_count; + +/// @brief Dynamic Shared Object Handle. +Kernel::UIntPtr __dso_handle; + +EXTERN_C void __cxa_pure_virtual() +{ + Kernel::kcout << "newoskrnl: C++ placeholder method.\n"; +} + +EXTERN_C void ___chkstk_ms(void) +{ + Kernel::err_bug_check_raise(); + Kernel::err_bug_check(); +} + +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 + +#endif // ifdef __NEWOS_AMD64__ diff --git a/dev/ZKA/Sources/CxxAbi-ARM64.cxx b/dev/ZKA/Sources/CxxAbi-ARM64.cxx new file mode 100644 index 00000000..b0cb7354 --- /dev/null +++ b/dev/ZKA/Sources/CxxAbi-ARM64.cxx @@ -0,0 +1,74 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#ifdef __NEWOS_ARM64__ + +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/CxxAbi.hxx> +#include <KernelKit/LPC.hxx> + +EXTERN_C +{ +#include <limits.h> +} + +int const cUninitialized = 0; +int const cBeingInitialized = -1; +int const cEpochStart = INT_MIN; + +EXTERN_C +{ + int _Init_global_epoch = cEpochStart; + __thread int _Init_thread_epoch = cEpochStart; +} + +Kernel::UInt32 const cNKTimeout = 100; // ms + +EXTERN_C void __cdecl _Init_thread_wait(Kernel::UInt32 const timeout) +{ + MUST_PASS(timeout != INT_MAX); +} + +EXTERN_C void __cdecl _Init_thread_header(int* const pOnce) noexcept +{ + if (*pOnce == cUninitialized) + { + *pOnce = cBeingInitialized; + } + else + { + while (*pOnce == cBeingInitialized) + { + _Init_thread_wait(cNKTimeout); + + if (*pOnce == cUninitialized) + { + *pOnce = cBeingInitialized; + return; + } + } + _Init_thread_epoch = _Init_global_epoch; + } +} + +EXTERN_C void __cdecl _Init_thread_abort(int* const pOnce) noexcept +{ + *pOnce = cUninitialized; +} + +EXTERN_C void __cdecl _Init_thread_footer(int* const pOnce) noexcept +{ + ++_Init_global_epoch; + *pOnce = _Init_global_epoch; + _Init_thread_epoch = _Init_global_epoch; +} + +EXTERN_C void _purecall() +{ + Kernel::kcout << "newoskrnl: C++ placeholder method.\n"; +} + +#endif // ifdef __NEWOS_ARM64__ diff --git a/dev/ZKA/Sources/Defines.cxx b/dev/ZKA/Sources/Defines.cxx new file mode 100644 index 00000000..2e8dde86 --- /dev/null +++ b/dev/ZKA/Sources/Defines.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Defines.hxx> diff --git a/dev/ZKA/Sources/DeviceManager.cxx b/dev/ZKA/Sources/DeviceManager.cxx new file mode 100644 index 00000000..229e0fb7 --- /dev/null +++ b/dev/ZKA/Sources/DeviceManager.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DeviceManager.hxx> diff --git a/dev/ZKA/Sources/DriveManager.cxx b/dev/ZKA/Sources/DriveManager.cxx new file mode 100644 index 00000000..90bf12f8 --- /dev/null +++ b/dev/ZKA/Sources/DriveManager.cxx @@ -0,0 +1,151 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hxx> +#include <KernelKit/DriveManager.hxx> +#include <Modules/ATA/ATA.hxx> +#include <Modules/AHCI/AHCI.hxx> +#include <NewKit/Utils.hxx> + +/// @file DriveManager.cxx +/// @brief Kernel drive manager. + +namespace Kernel +{ + 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* io_drive_kind(Void) + { + return "ATA-PIO"; + } +#endif + +#ifdef __ATA_DMA__ + const Char* io_drive_kind(Void) + { + return "ATA-DMA"; + } +#endif + +#ifdef __AHCI__ + const Char* io_drive_kind(Void) + { + return "AHCI"; + } +#endif + + /// @brief Unimplemented drive. + /// @param pckt + /// @return + Void io_drv_unimplemented(DriveTrait::DrivePacket* pckt) + { + } + + /// @brief Makes a new drive. + /// @return the new drive. + DriveTrait io_construct_drive() noexcept + { + DriveTrait trait; + + rt_copy_memory((VoidPtr) "/Mount/Null", trait.fName, rt_string_len("/Mount/Null")); + trait.fKind = kInvalidDrive; + + trait.fInput = io_drv_unimplemented; + trait.fOutput = io_drv_unimplemented; + trait.fVerify = io_drv_unimplemented; + trait.fDriveKind = io_drive_kind; + + return trait; + } + + /// @brief Fetches the main drive. + /// @return the new drive. + DriveTrait io_construct_main_drive() noexcept + { + DriveTrait trait; + + rt_copy_memory((VoidPtr) "MainDisk", trait.fName, rt_string_len("MainDisk")); + trait.fKind = kMassStorage; + + trait.fInput = ke_drv_input; + trait.fOutput = ke_drv_output; + trait.fVerify = ke_drv_check_disk; + trait.fDriveKind = io_drive_kind; + + kcout << "newoskrnl: Construct drive with success.\r"; + + return trait; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/ErrorOr.cxx b/dev/ZKA/Sources/ErrorOr.cxx new file mode 100644 index 00000000..0205506d --- /dev/null +++ b/dev/ZKA/Sources/ErrorOr.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/ErrorOr.hxx> + +/***********************************************************************************/ +/// @file ErrorOr.cxx /// +/// @brief Error Or Value class. /// +/***********************************************************************************/ diff --git a/dev/ZKA/Sources/FS/NewFS.cxx b/dev/ZKA/Sources/FS/NewFS.cxx new file mode 100644 index 00000000..90f48eb2 --- /dev/null +++ b/dev/ZKA/Sources/FS/NewFS.cxx @@ -0,0 +1,1054 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#ifdef __FSKIT_USE_NEWFS__ + +#include <Modules/AHCI/AHCI.hxx> +#include <Modules/ATA/ATA.hxx> +#include <Modules/Flash/Flash.hxx> +#include <FSKit/NewFS.hxx> +#include <KernelKit/LPC.hxx> +#include <NewKit/Crc32.hxx> +#include <NewKit/KernelCheck.hxx> +#include <NewKit/String.hxx> +#include <NewKit/Utils.hxx> +#include <FirmwareKit/EPM.hxx> +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/User.hxx> + +using namespace Kernel; + +#ifdef __ED__ +/** + Define those external symbols, to make the editor shutup +*/ + +/// @brief get sector count. +Kernel::SizeT drv_std_get_sector_count(); + +/// @brief get device size. +Kernel::SizeT drv_std_get_drv_size(); + +#endif + +///! BUGS: 0 + +/***********************************************************************************/ +/// This file implements the New File System. +/// New File System implements a B-Tree based algortihm. +/// \\ +/// \\Path1\\ \\ath2\\ +/// \\readme.rtf \\ListContents.pef \\readme.lnk <-- symlink. +/// \\Path1\\readme.rtf +/***********************************************************************************/ + +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 NFS_FORK_STRUCT* NewFSParser::CreateFork(_Input NFS_CATALOG_STRUCT* catalog, + _Input NFS_FORK_STRUCT& theFork) +{ + if (catalog && theFork.ForkName[0] != 0 && + theFork.DataSize == kNewFSForkSize) + { + Lba lba = (theFork.Kind == kNewFSDataForkKind) ? catalog->DataFork + : catalog->ResourceFork; + + kcout << "newoskrnl: fork lba: " << hex_number(lba) << endl; + + if (lba <= kNewFSCatalogStartAddress) + return nullptr; + + auto drv = sMountpointInterface.A(); + + /// special treatment. + rt_copy_memory((VoidPtr) "fs/newfs-packet", drv.fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + NFS_FORK_STRUCT curFork{0}; + NFS_FORK_STRUCT 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(NFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &curFork; + + drv.fInput(&drv.fPacket); + + kcout << "newoskrnl: next fork: " << hex_number(curFork.NextSibling) << endl; + + if (curFork.Flags == kNewFSFlagCreated) + { + kcout << "newoskrnl: Fork already exists.\r"; + + /// sanity check. + if (StringBuilder::Equals(curFork.ForkName, theFork.ForkName) && + StringBuilder::Equals(curFork.CatalogName, catalog->Name)) + return nullptr; + + kcout << "newoskrnl: 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(NFS_FORK_STRUCT); + 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(NFS_FORK_STRUCT) * cForkPadding; + theFork.PreviousSibling = lbaOfPreviousFork; + theFork.NextSibling = theFork.DataOffset - theFork.DataSize; + + drv.fPacket.fLba = lba; + drv.fPacket.fPacketSize = sizeof(NFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &theFork; + + drv.fOutput(&drv.fPacket); + + /// log what we have now. + kcout << "newoskrnl: Wrote fork data at: " << hex_number(theFork.DataOffset) + << endl; + + kcout << "newoskrnl: 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 NFS_FORK_STRUCT* NewFSParser::FindFork(_Input NFS_CATALOG_STRUCT* catalog, + _Input const Char* name, + Boolean isDataFork) +{ + auto drv = sMountpointInterface.A(); + NFS_FORK_STRUCT* theFork = nullptr; + + Lba lba = isDataFork ? catalog->DataFork : catalog->ResourceFork; + + while (lba != 0) + { + drv.fPacket.fLba = lba; + drv.fPacket.fPacketSize = sizeof(NFS_FORK_STRUCT); + 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: + ErrLocal() = kErrorDiskReadOnly; + break; + case 2: + ErrLocal() = kErrorDiskIsFull; + break; + ErrLocal() = 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 NFS_CATALOG_STRUCT* 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 NFS_CATALOG_STRUCT* NewFSParser::CreateCatalog(_Input const Char* name, + _Input const Int32& flags, + _Input const Int32& kind) +{ + kcout << "newoskrnl: CreateCatalog(...)\r"; + + Lba outLba = 0UL; + + kcout << "newoskrnl: Checking for extension...\r"; + + /// 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; + + NFS_CATALOG_STRUCT* copyExists = this->FindCatalog(name, outLba); + + if (copyExists) + { + kcout << "newoskrnl: Copy already exists.\r"; + ErrLocal() = kErrorFileExists; + + return copyExists; + } + + Char parentName[kNewFSNodeNameLen] = {0}; + + for (SizeT indexName = 0UL; indexName < rt_string_len(name); ++indexName) + { + parentName[indexName] = name[indexName]; + } + + if (*parentName == 0) + { + kcout << "newoskrnl: Parent name is NUL.\r"; + ErrLocal() = 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 it. + parentName[--indexReverseCopy] = 0; + + // mandatory / character, zero it. + parentName[--indexReverseCopy] = 0; + + while (parentName[indexReverseCopy] != NewFilesystemHelper::Separator()) + { + parentName[indexReverseCopy] = 0; + --indexReverseCopy; + } + + NFS_CATALOG_STRUCT* catalog = this->FindCatalog(parentName, outLba); + + if (catalog && catalog->Kind == kNewFSCatalogKindFile) + { + kcout << "newoskrnl: Parent name is file.\r"; + delete catalog; + return nullptr; + } + else if (!catalog) + { + outLba = kNewFSCatalogStartAddress; + } + + constexpr SizeT cDefaultForkSize = kNewFSForkSize; + + NFS_CATALOG_STRUCT* catalogChild = new NFS_CATALOG_STRUCT(); + + Int32 flagsList = flags; + + if (flagsList & kNewFSCatalogKindMetaFile) + { + if (UserManager::The()->GetCurrent() != UserManager::The()->fRootUser && + UserManager::The()->fRootUser) + { + delete catalogChild; + return nullptr; + } + } + + catalogChild->ResourceForkSize = cDefaultForkSize; + catalogChild->DataForkSize = cDefaultForkSize; + + catalogChild->NextSibling = outLba; + catalogChild->PrevSibling = outLba; + catalogChild->Kind = kind; + catalogChild->Flags = kNewFSFlagCreated | flagsList; + + rt_copy_memory((VoidPtr)name, (VoidPtr)catalogChild->Name, + rt_string_len(name)); + + UInt16 catalogBuf[kNewFSSectorSz] = {0}; + + auto drive = sMountpointInterface.A(); + + 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); + + NFS_CATALOG_STRUCT* nextSibling = (NFS_CATALOG_STRUCT*)catalogBuf; + + startFree = nextSibling->NextSibling; + + catalogChild->PrevSibling = outLba; + + drive.fPacket.fLba = startFree; + drive.fInput(&drive.fPacket); + + while (drive.fPacket.fPacketGood) + { + nextSibling = reinterpret_cast<NFS_CATALOG_STRUCT*>(catalogBuf); + + if (startFree <= kNewFSStartLba) + { + delete catalogChild; + delete catalog; + + return nullptr; + } + + // ========================== // + // allocate catalog now... + // ========================== // + if (nextSibling->Flags != kNewFSFlagCreated) + { + Char sectorBufPartBlock[kNewFSSectorSz] = {0}; + + drive.fPacket.fPacketContent = sectorBufPartBlock; + drive.fPacket.fPacketSize = kNewFSSectorSz; + drive.fPacket.fLba = kNewFSStartLba; + + drive.fInput(&drive.fPacket); + + constexpr auto cNewFSCatalogPadding = 4; + + NFS_ROOT_PARTITION_BLOCK* partBlock = (NFS_ROOT_PARTITION_BLOCK*)sectorBufPartBlock; + + if (partBlock->FreeCatalog < 1) + { + delete catalogChild; + return nullptr; + } + + catalogChild->DataFork = partBlock->DiskSize - partBlock->StartCatalog; + + catalogChild->ResourceFork = catalogChild->DataFork; + + catalogChild->NextSibling = + startFree + (sizeof(NFS_CATALOG_STRUCT) * cNewFSCatalogPadding); + + drive.fPacket.fPacketContent = catalogChild; + drive.fPacket.fPacketSize = sizeof(NFS_CATALOG_STRUCT); + drive.fPacket.fLba = startFree; + + drive.fOutput(&drive.fPacket); + + drive.fPacket.fPacketContent = catalogBuf; + drive.fPacket.fPacketSize = kNewFSSectorSz; + drive.fPacket.fLba = + startFree - (sizeof(NFS_CATALOG_STRUCT) * cNewFSCatalogPadding); + + drive.fInput(&drive.fPacket); + + nextSibling->NextSibling = startFree; + + drive.fOutput(&drive.fPacket); + + kcout << "newoskrnl: Create new catalog, status: " + << hex_number(catalogChild->Flags) << endl; + kcout << "newoskrnl: Create new catalog, status: " << catalogChild->Name + << endl; + + drive.fPacket.fPacketContent = sectorBufPartBlock; + drive.fPacket.fPacketSize = kNewFSSectorSz; + drive.fPacket.fLba = kNewFSStartLba; + + 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(NFS_CATALOG_STRUCT) * 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 ErrLocal(). +bool NewFSParser::Format(_Input _Output DriveTrait* drive, _Input const Lba endLba, _Input const Int32 flags, const Char* part_name) +{ + if (*part_name == 0 || + endLba == 0) + return false; + + // verify disk. + drive->fVerify(&drive->fPacket); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + // if disk isn't good, then error out. + if (false == drive->fPacket.fPacketGood) + { + ErrLocal() = kErrorDiskIsCorrupted; + return false; + } + + Char sectorBuf[kNewFSSectorSz] = {0}; + + Lba start = kNewFSStartLba; + + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = start; + + drive->fInput(&drive->fPacket); + + if (flags & kNewFSPartitionTypeBoot) + { + // make it bootable when needed. + Char bufEpmHdr[kNewFSSectorSz] = {0}; + + BOOT_BLOCK_STRUCT* epmBoot = (BOOT_BLOCK_STRUCT*)bufEpmHdr; + + constexpr auto cFsName = "NewFS"; + constexpr auto cBlockName = "ZKA:"; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(cFsName)), epmBoot->Fs, rt_string_len(cFsName)); + + epmBoot->FsVersion = kNewFSVersionInteger; + epmBoot->LbaStart = 0; + epmBoot->SectorSz = kNewFSSectorSz; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(cBlockName)), epmBoot->Name, rt_string_len(cBlockName)); + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(kEPMMagic)), epmBoot->Magic, rt_string_len(kEPMMagic)); + + Lba outEpmLba = kEpmBase; + + Char buf[kNewFSSectorSz]; + + Lba prevStart = 0; + SizeT cnt = 0; + + while (drive->fPacket.fPacketGood) + { + drive->fPacket.fPacketContent = buf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = outEpmLba; + + drive->fInput(&drive->fPacket); + + if (buf[0] == 0) + { + epmBoot->LbaStart = prevStart; + + if (epmBoot->LbaStart) + epmBoot->LbaStart = outEpmLba; + + epmBoot->LbaEnd = endLba; + epmBoot->NumBlocks = cnt; + + drive->fPacket.fPacketContent = bufEpmHdr; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = outEpmLba; + + drive->fOutput(&drive->fPacket); + + break; + } + else + { + prevStart = ((BOOT_BLOCK_STRUCT*)buf)->LbaStart + ((BOOT_BLOCK_STRUCT*)buf)->LbaEnd; + } + + outEpmLba += sizeof(BOOT_BLOCK_STRUCT); + ++cnt; + } + } + + // disk isnt faulty and data has been fetched. + while (drive->fPacket.fPacketGood) + { + NFS_ROOT_PARTITION_BLOCK* partBlock = (NFS_ROOT_PARTITION_BLOCK*)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 = part_name; + + rt_copy_memory((VoidPtr)kNewFSIdent, (VoidPtr)partBlock->Ident, + kNewFSIdentLen); + + rt_copy_memory((VoidPtr)cUntitledHD, (VoidPtr)partBlock->PartitionName, + rt_string_len(cUntitledHD)); + + SizeT catalogCount = 0UL; + + 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(NFS_CATALOG_STRUCT); + partBlock->SectorCount = sectorCount; + partBlock->DiskSize = diskSize; + partBlock->FreeCatalog = sectorCount / sizeof(NFS_CATALOG_STRUCT); + + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = kNewFSStartLba; + + drive->fOutput(&drive->fPacket); + + kcout << "newoskrnl: drive kind: " << drive->fDriveKind() << endl; + + kcout << "newoskrnl: partition name: " << partBlock->PartitionName << endl; + kcout << "newoskrnl: start: " << hex_number(partBlock->StartCatalog) << endl; + kcout << "newoskrnl: number of catalogs: " << hex_number(partBlock->CatalogCount) << endl; + kcout << "newoskrnl: free catalog: " << hex_number(partBlock->FreeCatalog) << endl; + kcout << "newoskrnl: free sectors: " << hex_number(partBlock->FreeSectors) << endl; + kcout << "newoskrnl: sector size: " << hex_number(partBlock->SectorSize) << endl; + + // write the root catalog. + this->CreateCatalog(kNewFSRoot, 0, kNewFSCatalogKindDir); + + return true; + } + + kcout << "newoskrnl: partition block already exists.\r"; + + start += partBlock->DiskSize; + + drive->fPacket.fPacketContent = sectorBuf; + drive->fPacket.fPacketSize = kNewFSSectorSz; + drive->fPacket.fLba = start; + + drive->fInput(&drive->fPacket); + } + + return false; +} + +/// @brief Writes the data fork into a specific catalog. +/// @param catalog the catalog itself +/// @param data the data. +/// @return if the catalog w rote the contents successfully. +bool NewFSParser::WriteCatalog(_Input _Output NFS_CATALOG_STRUCT* catalog, voidPtr data, SizeT sizeOfData, _Input const Char* forkName) +{ + NFS_FORK_STRUCT forkData{0}; + + auto drive = sMountpointInterface.A(); + + 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); + + NFS_FORK_STRUCT forkDataIn{0}; + + // sanity check of the fork position as the condition to run the loop. + while (startFork >= kNewFSCatalogStartAddress) + { + drive.fPacket.fPacketContent = &forkDataIn; + drive.fPacket.fPacketSize = sizeof(NFS_FORK_STRUCT); + drive.fPacket.fLba = startFork; + + drive.fInput(&drive.fPacket); + + kcout << "newoskrnl: fork name: " << forkName << endl; + + // check the fork, if it's position is valid. + if (forkDataIn.DataOffset <= kNewFSCatalogStartAddress) + { + ErrLocal() = kErrorDiskIsCorrupted; + + kcout << "newoskrnl: Invalid fork offset.\r"; + + return false; + } + + if (forkData.Flags != kNewFSFlagUnallocated && + forkData.Flags != kNewFSFlagDeleted && + StringBuilder::Equals(forkData.ForkName, forkName) && + StringBuilder::Equals(forkData.CatalogName, catalog->Name)) + { + if (forkDataIn.DataSize < sizeOfData) + { + startFork = forkData.NextSibling; + continue; + } + + drive.fPacket.fPacketContent = data; + drive.fPacket.fPacketSize = sizeOfData; + drive.fPacket.fLba = forkData.DataOffset; + + kcout << "newoskrnl: data offset: " << hex_number(forkData.DataOffset) << endl; + + drive.fOutput(&drive.fPacket); + + return true; + } + else + { + // ===================================================== // + // Store size of blob now. + // ===================================================== // + forkData.DataSize = sizeOfData; + + if (sizeOfData < kNewFSForkSize) + forkData.DataSize = kNewFSForkSize; + + drive.fPacket.fPacketContent = data; + drive.fPacket.fPacketSize = sizeOfData; + drive.fPacket.fLba = forkData.DataOffset; + + kcout << "newoskrnl: data offset: " << hex_number(forkData.DataOffset) << endl; + + drive.fOutput(&drive.fPacket); + + forkData.Flags = kNewFSFlagCreated; + + drive.fPacket.fPacketContent = &forkData; + drive.fPacket.fPacketSize = sizeof(NFS_FORK_STRUCT); + drive.fPacket.fLba = startFork; + + drive.fOutput(&drive.fPacket); + + kcout << "newoskrnl: wrote fork at offset: " << hex_number(forkData.DataOffset) << endl; + + delete catalog; + + return true; + } + + startFork = forkData.NextSibling; + } + + return false; +} + +/// @brief +/// @param catalogName the catalog name. +/// @return the newly found catalog. +_Output NFS_CATALOG_STRUCT* NewFSParser::FindCatalog(_Input const Char* catalogName, + Lba& outLba) +{ + kcout << "newoskrnl: start finding catalog...\r"; + + Char* sectorBuf = new Char[sizeof(NFS_ROOT_PARTITION_BLOCK)]; + auto drive = sMountpointInterface.A(); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + drive.fPacket.fPacketContent = sectorBuf; + drive.fPacket.fPacketSize = sizeof(NFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fLba = kNewFSStartLba; + + drive.fInput(&drive.fPacket); + + NFS_ROOT_PARTITION_BLOCK* part = (NFS_ROOT_PARTITION_BLOCK*)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(NFS_CATALOG_STRUCT); + + 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; + } + + NFS_CATALOG_STRUCT* parentCatalog = this->FindCatalog(parentName, outLba); + + if (parentCatalog && + !StringBuilder::Equals(parentName, NewFilesystemHelper::Root())) + { + startCatalogList = outLba; + delete parentCatalog; + + localSearchFirst = true; + } + else if (parentCatalog) + { + delete parentCatalog; + } + } + + kcout << "newoskrnl: fetching catalog...\r"; + +_NewFSSearchThroughCatalogList: + while (drive.fPacket.fPacketGood) + { + NFS_CATALOG_STRUCT* catalog = (NFS_CATALOG_STRUCT*)sectorBuf; + + if (StringBuilder::Equals(catalogName, catalog->Name)) + { + /// ignore unallocated catalog, break + if (catalog->Flags != kNewFSFlagCreated) + { + goto NewFSContinueSearch; + } + + NFS_CATALOG_STRUCT* catalogPtr = new NFS_CATALOG_STRUCT(); + rt_copy_memory(catalog, catalogPtr, sizeof(NFS_CATALOG_STRUCT)); + + kcout << "newoskrnl: found catalog at: " << hex_number(startCatalogList) << endl; + + outLba = startCatalogList; + delete[] sectorBuf; + return catalogPtr; + } + + NewFSContinueSearch: + startCatalogList = catalog->NextSibling; + + if (startCatalogList <= kNewFSStartLba) + break; + + drive.fPacket.fLba = startCatalogList; + drive.fPacket.fPacketContent = sectorBuf; + drive.fPacket.fPacketSize = sizeof(NFS_CATALOG_STRUCT); + + drive.fInput(&drive.fPacket); + } + + if (localSearchFirst) + { + localSearchFirst = false; + startCatalogList = cCtartCatalogList; + + goto _NewFSSearchThroughCatalogList; + } + + outLba = 0UL; + delete[] sectorBuf; + + return nullptr; +} + +/// @brief Get catalog from filesystem. +/// @param name the catalog's name/ +/// @return +_Output NFS_CATALOG_STRUCT* NewFSParser::GetCatalog(_Input const Char* name) +{ + Lba unused = 0; + return this->FindCatalog(name, unused); +} + +/// @brief Closes a catalog, (frees it). +/// @param catalog the catalog to close. +/// @return +Boolean NewFSParser::CloseCatalog(_Input _Output NFS_CATALOG_STRUCT* catalog) +{ + if (!catalog) + return false; + + delete catalog; + catalog = nullptr; + + return true; +} + +/// @brief Mark catalog as removed. +/// @param catalog The catalog structure. +/// @return if the catalog was removed or not. +Boolean NewFSParser::RemoveCatalog(_Input const Char* catalogName) +{ + if (!catalogName || + StringBuilder::Equals(catalogName, NewFilesystemHelper::Root())) + { + ErrLocal() = kErrorInternal; + return false; + } + + Lba outLba = 0; + auto catalog = this->FindCatalog(catalogName, outLba); + + if (outLba >= kNewFSCatalogStartAddress || + catalog->Flags == kNewFSFlagCreated) + { + catalog->Flags = kNewFSFlagDeleted; + + auto drive = sMountpointInterface.A(); + + 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(NFS_CATALOG_STRUCT); // size of catalog. roughly the sector size. + drive.fPacket.fPacketContent = catalog; // the catalog itself. + + drive.fOutput(&drive.fPacket); // send packet. + + Char partitionBlockBuf[sizeof(NFS_ROOT_PARTITION_BLOCK)] = {0}; + + drive.fPacket.fLba = kNewFSStartLba; + drive.fPacket.fPacketContent = partitionBlockBuf; + drive.fPacket.fPacketSize = sizeof(NFS_ROOT_PARTITION_BLOCK); + + drive.fInput(&drive.fPacket); + + NFS_ROOT_PARTITION_BLOCK* partBlock = + reinterpret_cast<NFS_ROOT_PARTITION_BLOCK*>(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 NFS_CATALOG_STRUCT* catalog, + _Input SizeT dataSz, + _Input const Char* forkName) +{ + if (!catalog) + { + ErrLocal() = kErrorFileNotFound; + return nullptr; + } + + Lba dataForkLba = catalog->DataFork; + Size dataForkSize = catalog->DataForkSize; + + kcout << "newoskrnl: catalog " << catalog->Name + << ", fork: " << hex_number(dataForkLba) << endl; + + Char* sectorBuf = new Char[sizeof(NFS_FORK_STRUCT)]; + auto drive = sMountpointInterface.A(); + + rt_copy_memory((VoidPtr) "fs/newfs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/newfs-packet")); + + NFS_FORK_STRUCT* forkData = nullptr; + + while (dataForkLba >= kNewFSCatalogStartAddress) + { + drive.fPacket.fLba = dataForkLba; + drive.fPacket.fPacketSize = sizeof(NFS_FORK_STRUCT); + drive.fPacket.fPacketContent = sectorBuf; + + drive.fInput(&drive.fPacket); + + forkData = (NFS_FORK_STRUCT*)sectorBuf; + + kcout << "newoskrnl: 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 NFS_CATALOG_STRUCT* catalog, SizeT off) +{ + if (!catalog) + { + ErrLocal() = kErrorFileNotFound; + return false; + } + + ErrLocal() = 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 NFS_CATALOG_STRUCT* catalog) +{ + if (!catalog) + { + ErrLocal() = kErrorFileNotFound; + return 0; + } + + ErrLocal() = kErrorUnimplemented; + return 0; +} + +namespace Kernel::Detail +{ + /***********************************************************************************/ + /// @brief Construct NewFS drives. + /***********************************************************************************/ + Boolean fs_init_newfs(Void) noexcept + { + kcout << "newoskrnl: Creating drives...\r"; + + sMountpointInterface.A() = io_construct_main_drive(); + sMountpointInterface.B() = io_construct_drive(); + sMountpointInterface.C() = io_construct_drive(); + sMountpointInterface.D() = io_construct_drive(); + + kcout << "newoskrnl: Testing main drive...\r"; + + sMountpointInterface.A().fVerify(&sMountpointInterface.A().fPacket); + + kcout << "newoskrnl: Testing main drive [ OK ]...\r"; + + return true; + } +} // namespace Kernel::Detail + +#endif // ifdef __FSKIT_USE_NEWFS__ diff --git a/dev/ZKA/Sources/FS/compile_flags.txt b/dev/ZKA/Sources/FS/compile_flags.txt new file mode 100644 index 00000000..39b236a9 --- /dev/null +++ b/dev/ZKA/Sources/FS/compile_flags.txt @@ -0,0 +1,6 @@ +-nostdlib +-ffreestanding +-std=c++20 +-I./ +-I../ +-D__ED__ diff --git a/dev/ZKA/Sources/FileManager.cxx b/dev/ZKA/Sources/FileManager.cxx new file mode 100644 index 00000000..aa8fca2a --- /dev/null +++ b/dev/ZKA/Sources/FileManager.cxx @@ -0,0 +1,196 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/FileManager.hxx> +#include <NewKit/Utils.hxx> + +/// BUGS: 0 +//! @brief File manager for Kernel. + +namespace Kernel +{ + STATIC FilesystemManagerInterface* kMounted = nullptr; + + /// @brief FilesystemManager getter. + /// @return The mounted filesystem. + _Output FilesystemManagerInterface* FilesystemManagerInterface::GetMounted() + { + return kMounted; + } + + /// @brief Unmount filesystem. + /// @return The unmounted filesystem. + _Output FilesystemManagerInterface* FilesystemManagerInterface::Unmount() + { + if (kMounted) + { + auto mount = kMounted; + kMounted = nullptr; + + return mount; + } + + return nullptr; + } + + /// @brief Mount filesystem. + /// @param mount_ptr The filesystem to mount. + /// @return if it succeeded true, otherwise false. + bool FilesystemManagerInterface::Mount(_Input FilesystemManagerInterface* mount_ptr) + { + if (mount_ptr != nullptr) + { + kMounted = mount_ptr; + return true; + } + + return false; + } + +#ifdef __FSKIT_USE_NEWFS__ + /// @brief Opens a new file. + /// @param path + /// @param r + /// @return + _Output NodePtr NewFilesystemManager::Open(_Input const Char* path, _Input 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(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, _Input SizeT size) + { + if (!node) + return; + if (!size) + return; + + constexpr auto cDataForkName = kNewFSDataFork; + this->Write(cDataForkName, node, data, flags, size); + } + + /// @brief Read from filesystem fork. + /// @param node the catalog node. + /// @param flags the flags with it. + /// @param sz the size to read. + /// @return + _Output VoidPtr NewFilesystemManager::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) + { + if (!node) + return nullptr; + if (!size) + return nullptr; + + constexpr auto cDataForkName = kNewFSDataFork; + return this->Read(cDataForkName, node, flags, size); + } + + Void NewFilesystemManager::Write(_Input const Char* name, + _Input NodePtr node, + _Input VoidPtr data, + _Input Int32 flags, + _Input SizeT size) + { + if (!size || + size > kNewFSForkSize) + return; + + if (!data) + return; + + NEWOS_UNUSED(flags); + + if ((reinterpret_cast<NFS_CATALOG_STRUCT*>(node))->Kind == kNewFSCatalogKindFile) + fImpl->WriteCatalog(reinterpret_cast<NFS_CATALOG_STRUCT*>(node), data, size, + name); + } + + _Output VoidPtr NewFilesystemManager::Read(_Input const Char* name, + _Input NodePtr node, + _Input Int32 flags, + _Input SizeT sz) + { + if (sz > kNewFSForkSize) + return nullptr; + + if (!sz) + return nullptr; + + NEWOS_UNUSED(flags); + + if ((reinterpret_cast<NFS_CATALOG_STRUCT*>(node))->Kind == kNewFSCatalogKindFile) + return fImpl->ReadCatalog(reinterpret_cast<NFS_CATALOG_STRUCT*>(node), sz, + name); + + return nullptr; + } + + /// @brief Seek from Catalog. + /// @param node + /// @param off + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output Bool NewFilesystemManager::Seek(NodePtr node, SizeT off) + { + if (!node || off == 0) + return false; + + return fImpl->Seek(reinterpret_cast<NFS_CATALOG_STRUCT*>(node), off); + } + + /// @brief Tell where the catalog is. + /// @param node + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output SizeT NewFilesystemManager::Tell(NodePtr node) + { + if (!node) + return kNPos; + + return fImpl->Tell(reinterpret_cast<NFS_CATALOG_STRUCT*>(node)); + } + + /// @brief Rewinds the catalog. + /// @param node + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output Bool NewFilesystemManager::Rewind(NodePtr node) + { + if (!node) + return false; + + return this->Seek(node, 0); + } + + /// @brief Returns the filesystem parser. + /// @return the Filesystem parser class. + _Output NewFSParser* NewFilesystemManager::GetParser() noexcept + { + return fImpl; + } +#endif // __FSKIT_USE_NEWFS__ +} // namespace Kernel diff --git a/dev/ZKA/Sources/Framebuffer.cxx b/dev/ZKA/Sources/Framebuffer.cxx new file mode 100644 index 00000000..76fe7172 --- /dev/null +++ b/dev/ZKA/Sources/Framebuffer.cxx @@ -0,0 +1,113 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + + File: Framebuffer.cxx + Purpose: Framebuffer object + + Revision History: + + 01/02/24: Added file (amlel) + 02/02/24: Add documentation (amlel) + 07/07/07: Moved Framebuffer methods into Kernel:: + +------------------------------------------- */ + +#include <KernelKit/Framebuffer.hxx> +#include <HintKit/CompilerHint.hxx> + +/** + * @brief Framebuffer object implementation. + * + */ + +namespace Kernel +{ + Framebuffer::Framebuffer(_Input Ref<FramebufferContext*>& addr) + : fFrameBufferAddr(addr) + { + } + + /** + * @brief Get Pixel at **pos** + * + * @param pos position of pixel. + * @return volatile* + */ + _Output volatile UIntPtr* Framebuffer::operator[](_Input 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 + _Output 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. + _Output Ref<FramebufferContext*>& Framebuffer::Leak() + { + return this->fFrameBufferAddr; + } + + /// @brief Draws a rectangle. + /// @param width + /// @param height + /// @param x + /// @param y + /// @param color + /// @return + _Output Framebuffer& Framebuffer::DrawRect(SizeT width, SizeT height, SizeT x, SizeT y, UInt32 color) + { + for (Kernel::SizeT i = x; i < width + x; ++i) + { + for (Kernel::SizeT u = y; u < height + y; ++u) + { + *(((volatile Kernel::UInt32*)(fFrameBufferAddr.Leak()->fBase + + 4 * fFrameBufferAddr.Leak()->fBpp * i + + 4 * u))) = color; + } + } + + return *this; + } + + /// @brief Put a pixel on the screen. + /// @param x + /// @param y + /// @param color + /// @return + _Output Framebuffer& Framebuffer::PutPixel(SizeT x, SizeT y, UInt32 color) + { + *(((volatile Kernel::UInt32*)(fFrameBufferAddr.Leak()->fBase + + 4 * fFrameBufferAddr.Leak()->fBpp * x + + 4 * y))) = color; + + return *this; + } + + const UInt32 kRgbRed = 0x000000FF; + const UInt32 kRgbGreen = 0x0000FF00; + const UInt32 kRgbBlue = 0x00FF0000; + const UInt32 kRgbBlack = 0x00000000; + const UInt32 kRgbWhite = 0xFFFFFFFF; +} // namespace Kernel diff --git a/dev/ZKA/Sources/GUIDWizard.cxx b/dev/ZKA/Sources/GUIDWizard.cxx new file mode 100644 index 00000000..bdd274a4 --- /dev/null +++ b/dev/ZKA/Sources/GUIDWizard.cxx @@ -0,0 +1,72 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + + File: GUIDWizard.cxx + Purpose: GUID helper code + + Revision History: + +------------------------------------------- */ + +#include <CFKit/GUIDWizard.hxx> +#include <NewKit/Ref.hxx> + +// begin of ascii 'readable' characters. (A, C, C, 1, 2) +#define kAsciiBegin 47 +// @brief Size of UUID. +#define kUUIDSize 37 + +namespace Kernel::XRN::Version1 +{ + auto cf_make_sequence(const ArrayList<UInt32>& 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->fMs4[0] = uuidSeq[3]; + sequenceReference->fMs4[1] = uuidSeq[4]; + sequenceReference->fMs4[2] = uuidSeq[5]; + sequenceReference->fMs4[3] = uuidSeq[6]; + sequenceReference->fMs4[4] = uuidSeq[7]; + sequenceReference->fMs4[5] = uuidSeq[8]; + sequenceReference->fMs4[6] = uuidSeq[9]; + sequenceReference->fMs4[7] = uuidSeq[10]; + + return sequenceReference; + } + + // @brief Tries to make a guid out of a string. + // This function is not complete for now + auto cf_try_guid_to_string(Ref<GUIDSequence*>& seq) -> ErrorOr<Ref<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 Kernel::XRN::Version1 diff --git a/dev/ZKA/Sources/GUIDWrapper.cxx b/dev/ZKA/Sources/GUIDWrapper.cxx new file mode 100644 index 00000000..f87d792d --- /dev/null +++ b/dev/ZKA/Sources/GUIDWrapper.cxx @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <CFKit/GUIDWrapper.hxx> + +namespace Kernel::XRN +{ +} diff --git a/dev/ZKA/Sources/HError.cxx b/dev/ZKA/Sources/HError.cxx new file mode 100644 index 00000000..5ccf8aea --- /dev/null +++ b/dev/ZKA/Sources/HError.cxx @@ -0,0 +1,34 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/LPC.hxx> +#include <NewKit/KernelCheck.hxx> + +namespace Kernel +{ + STATIC Bool cRaise = false; + + /// @brief Does a system wide bug check. + /// @param void no params. + /// @return if error-free: true, otherwise false. + Boolean err_bug_check(void) noexcept + { + if (cRaise) + { + ke_stop(RUNTIME_CHECK_BAD_BEHAVIOR); + } + + return true; + } + + /// @brief Tells if we should raise a bug check not. + /// @param void + /// @return void + Void err_bug_check_raise(Void) noexcept + { + cRaise = true; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/Heap.cxx b/dev/ZKA/Sources/Heap.cxx new file mode 100644 index 00000000..de0c8a5c --- /dev/null +++ b/dev/ZKA/Sources/Heap.cxx @@ -0,0 +1,246 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hxx> +#include <KernelKit/LPC.hxx> +#include <KernelKit/Heap.hxx> +#include <NewKit/Crc32.hxx> +#include <NewKit/PageManager.hxx> + +//! @file KernelHeap.cxx +//! @brief Kernel heap allocator. + +#define kKernelHeapMagic (0xD4D7D5) +#define kKernelHeapHeaderPaddingSz (16U) + +namespace Kernel +{ + SizeT kHeapCount = 0UL; + PageManager kHeapPageManager; + Bool kOperationInProgress = No; + + namespace Detail + { + /// @brief Kernel heap information block. + /// Located before the address bytes. + /// | HIB | ADDRESS | + struct PACKED HEAP_INFORMATION_BLOCK final + { + ///! @brief 32-bit value which contains the magic number of the heap. + UInt32 fMagic; + ///! @brief Boolean value which tells if the heap 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; + /// @brief Is this a page pointer? + Boolean fPagePtr; + /// @brief Padding bytes for header. + UInt8 fPadding[kKernelHeapHeaderPaddingSz]; + }; + + typedef HEAP_INFORMATION_BLOCK* HEAP_INFORMATION_BLOCK_PTR; + + Void mm_alloc_init_timeout(Void) noexcept + { + kOperationInProgress = Yes; + } + + Void mm_alloc_fini_timeout(Void) noexcept + { + kOperationInProgress = No; + } + } // namespace Detail + + /// @brief Declare a new size for allocatedPtr. + /// @param allocatedPtr the pointer. + /// @return + voidPtr mm_realloc_ke_heap(voidPtr allocatedPtr, SizeT newSz) + { + if (!allocatedPtr || newSz < 1) + return nullptr; + + Detail::HEAP_INFORMATION_BLOCK_PTR heapInfoBlk = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)allocatedPtr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + heapInfoBlk->fTargetPtrSize = newSz; + + if (heapInfoBlk->fCRC32 > 0) + { + MUST_PASS(mm_protect_ke_heap(allocatedPtr)); + } + + return allocatedPtr; + } + + /// @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 newly allocated pointer. + VoidPtr mm_new_ke_heap(const SizeT sz, const bool rw, const bool user) + { + Detail::mm_alloc_init_timeout(); + + auto szFix = sz; + + if (szFix == 0) + ++szFix; + + kcout << "newoskrnl: allocating VMH page...\r"; + + auto wrapper = kHeapPageManager.Request(rw, user, false, szFix); + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + wrapper.VirtualAddress()); + + heap_info_ptr->fTargetPtrSize = szFix; + heap_info_ptr->fMagic = kKernelHeapMagic; + heap_info_ptr->fCRC32 = 0; // dont fill it for now. + heap_info_ptr->fTargetPtr = wrapper.VirtualAddress(); + heap_info_ptr->fPagePtr = 0; + + ++kHeapCount; + + Detail::mm_alloc_fini_timeout(); + + return reinterpret_cast<VoidPtr>(wrapper.VirtualAddress() + + sizeof(Detail::HEAP_INFORMATION_BLOCK)); + } + + /// @brief Makes a page heap. + /// @param heap_ptr + /// @return + Int32 mm_make_ke_page(VoidPtr heap_ptr) + { + if (kHeapCount < 1) + return -kErrorInternal; + if (((IntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)) <= 0) + return -kErrorInternal; + if (((IntPtr)heap_ptr - kBadPtr) < 0) + return -kErrorInternal; + + Detail::mm_alloc_init_timeout(); + + Detail::HEAP_INFORMATION_BLOCK_PTR heapInfoBlk = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + heapInfoBlk->fPagePtr = 1; + + Detail::mm_alloc_fini_timeout(); + + return 0; + } + + /// @brief Declare pointer as free. + /// @param heap_ptr the pointer. + /// @return + Int32 mm_delete_ke_heap(VoidPtr heap_ptr) + { + if (kHeapCount < 1) + return -kErrorInternal; + if (((IntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)) <= 0) + return -kErrorInternal; + if (((IntPtr)heap_ptr - kBadPtr) < 0) + return -kErrorInternal; + + Detail::mm_alloc_init_timeout(); + + Detail::HEAP_INFORMATION_BLOCK_PTR heapInfoBlk = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (heapInfoBlk && heapInfoBlk->fMagic == kKernelHeapMagic) + { + if (!heapInfoBlk->fPresent) + { + Detail::mm_alloc_fini_timeout(); + return -kErrorHeapNotPresent; + } + + if (heapInfoBlk->fCRC32 != 0) + { + if (heapInfoBlk->fCRC32 != + ke_calculate_crc32((Char*)heapInfoBlk->fTargetPtr, + heapInfoBlk->fTargetPtrSize)) + { + ke_stop(RUNTIME_CHECK_POINTER); + } + } + + heapInfoBlk->fTargetPtrSize = 0UL; + heapInfoBlk->fPresent = false; + heapInfoBlk->fTargetPtr = 0; + heapInfoBlk->fCRC32 = 0; + heapInfoBlk->fMagic = 0; + + PTEWrapper pageWrapper(false, false, false, reinterpret_cast<UIntPtr>(heapInfoBlk)); + Ref<PTEWrapper*> pteAddress{&pageWrapper}; + + kHeapPageManager.Free(pteAddress); + + --kHeapCount; + + Detail::mm_alloc_fini_timeout(); + + return 0; + } + + return -kErrorInternal; + } + + /// @brief Check if pointer is a valid kernel pointer. + /// @param heap_ptr the pointer + /// @return if it exists. + Boolean mm_is_valid_heap(VoidPtr heap_ptr) + { + if (kHeapCount < 1) + return false; + + if (heap_ptr) + { + Detail::HEAP_INFORMATION_BLOCK_PTR virtualAddress = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (virtualAddress->fPresent && virtualAddress->fMagic == kKernelHeapMagic) + { + return true; + } + } + + return false; + } + + /// @brief Protect the heap with a CRC value. + /// @param heap_ptr HIB pointer. + /// @return if it valid: point has crc now., otherwise fail. + Boolean mm_protect_ke_heap(VoidPtr heap_ptr) + { + if (heap_ptr) + { + Detail::HEAP_INFORMATION_BLOCK_PTR heapInfoBlk = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (heapInfoBlk->fPresent && kKernelHeapMagic == heapInfoBlk->fMagic) + { + heapInfoBlk->fCRC32 = + ke_calculate_crc32((Char*)heapInfoBlk->fTargetPtr, heapInfoBlk->fTargetPtrSize); + + return true; + } + } + + return false; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/IndexableProperty.cxx b/dev/ZKA/Sources/IndexableProperty.cxx new file mode 100644 index 00000000..f65e6f3f --- /dev/null +++ b/dev/ZKA/Sources/IndexableProperty.cxx @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +//! @brief Filesystem Indexer. + +#include <CompilerKit/CompilerKit.hxx> +#include <FSKit/IndexableProperty.hxx> +#include <NewKit/MutableArray.hxx> +#include <NewKit/Utils.hxx> + +/// @brief File Indexer. +/// BUGS: 0 + +#define kMaxLenIndexer 256 + +namespace Kernel +{ + namespace Indexer + { + IndexProperty& IndexableProperty::Leak() noexcept + { + return fIndex; + } + + Void IndexableProperty::AddFlag(Int16 flag) + { + fFlags |= flag; + } + + Void IndexableProperty::RemoveFlag(Int16 flag) + { + fFlags &= flag; + } + + Int16 IndexableProperty::HasFlag(Int16 flag) + { + return fFlags & flag; + } + + /// @brief Index a file into the indexer instance. + /// @param filename 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.Leak().Path, (VoidPtr)filename, filenameLen); + + kcout << "newoskrnl: filesystem: index new file: " << filename << endl; + } + } + } // namespace Indexer +} // namespace Kernel diff --git a/dev/ZKA/Sources/Json.cxx b/dev/ZKA/Sources/Json.cxx new file mode 100644 index 00000000..df0d0ef8 --- /dev/null +++ b/dev/ZKA/Sources/Json.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Json.hxx> + +using namespace Kernel; + +/// @brief Undefined object, is null in length. +cInitObject(Kernel::JsonType::kNull, Kernel::JsonType); diff --git a/dev/ZKA/Sources/KernelCheck.cxx b/dev/ZKA/Sources/KernelCheck.cxx new file mode 100644 index 00000000..27519369 --- /dev/null +++ b/dev/ZKA/Sources/KernelCheck.cxx @@ -0,0 +1,136 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hxx> +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/KernelCheck.hxx> +#include <NewKit/String.hxx> +#include <FirmwareKit/Handover.hxx> +#include <Modules/ACPI/ACPIFactoryInterface.hxx> + +#include <Modules/CoreCG/Accessibility.hxx> +#include <Modules/CoreCG/FbRenderer.hxx> +#include <Modules/CoreCG/TextRenderer.hxx> + +#define SetMem(dst, byte, sz) Kernel::rt_set_memory((Kernel::VoidPtr)dst, byte, sz) +#define CopyMem(dst, src, sz) Kernel::rt_copy_memory((Kernel::VoidPtr)src, (Kernel::VoidPtr)dst, sz) +#define MoveMem(dst, src, sz) Kernel::rt_copy_memory((Kernel::VoidPtr)src, (Kernel::VoidPtr)dst, sz) + +#define cWebsiteMacro "https://zka.nl/help" + +#include <BootKit/Vendor/Qr.hxx> + +/* Each error code is attributed with an ID, which will prompt a string onto the + * screen. Wait for debugger... */ + +namespace Kernel +{ + void ke_stop(const Kernel::Int& id) + { + CGInit(); + + auto panicBack = RGB(0xff, 0x3a, 0x3a); + auto panicTxt = RGB(0xff, 0xff, 0xff); + + CGDrawInRegion(panicBack, UIAccessibilty::The().Height(), UIAccessibilty::The().Width(), 0, 0); + + auto start_y = 10; + auto x = 10; + + cg_write_text("newoskrnl.dll stopped working properly so we had to stop.", start_y, x, panicTxt); + + CGFini(); + + // Show the QR code now. + + constexpr auto cVer = 4; + const auto cECC = qr::Ecc::H; + const auto cInput = cWebsiteMacro; + const auto cInputLen = rt_string_len(cWebsiteMacro); + + qr::Qr<cVer> encoder; + qr::QrDelegate encoderDelegate; + + encoder.encode(cInput, cInputLen, cECC, 0); // Manual mask 0 + + const auto cWhereStartX = (kHandoverHeader->f_GOP.f_Width - encoder.side_size()) - 20; + const auto cWhereStartY = (kHandoverHeader->f_GOP.f_Height - encoder.side_size()) / 2; + + // tell delegate to draw encoded QR now. + encoderDelegate.draw<cVer>(encoder, cWhereStartX, + cWhereStartY); + + start_y += 10; + + // show text according to error id. + + switch (id) + { + case RUNTIME_CHECK_PROCESS: { + cg_write_text("0x00000008 Process scheduler error (Catasrophic failure).", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_ACPI: { + cg_write_text("0x00000006 ACPI error.", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_POINTER: { + cg_write_text("0x00000000 Kernel heap error.", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_BAD_BEHAVIOR: { + cg_write_text("0x00000009 Undefined Behavior error.", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_BOOTSTRAP: { + cg_write_text("0x0000000A End of code.", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_HANDSHAKE: { + cg_write_text("0x00000005 Handshake error.", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_IPC: { + cg_write_text("0x00000003 Kernel IPC error.", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_INVALID_PRIVILEGE: { + cg_write_text("0x00000007 Kernel privilege violation.", start_y, x, panicTxt); + break; + case RUNTIME_CHECK_UNEXCPECTED: { + cg_write_text("0x0000000B Catasrophic failure.", start_y, x, panicTxt); + break; + } + case RUNTIME_CHECK_FAILED: { + cg_write_text("0x10000001 Assertion failed.", start_y, x, panicTxt); + break; + } + default: { + cg_write_text("0xFFFFFFFF Unknown error.", start_y, x, panicTxt); + break; + } + } + }; + + RecoveryFactory::Recover(); + } + + Void RecoveryFactory::Recover() noexcept + { + while (Yes) + { + asm volatile("cli; hlt"); + } + } + + void ke_runtime_check(bool expr, const char* file, const char* line) + { + if (!expr) + { + ke_stop(RUNTIME_CHECK_FAILED); // Runtime Check failed + } + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/LockDelegate.cxx b/dev/ZKA/Sources/LockDelegate.cxx new file mode 100644 index 00000000..f23c46d3 --- /dev/null +++ b/dev/ZKA/Sources/LockDelegate.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/LockDelegate.hxx> + +namespace Kernel +{ + /// Leave it empty for now. +} // namespace Kernel
\ No newline at end of file diff --git a/dev/ZKA/Sources/MP.cxx b/dev/ZKA/Sources/MP.cxx new file mode 100644 index 00000000..bf35f51e --- /dev/null +++ b/dev/ZKA/Sources/MP.cxx @@ -0,0 +1,256 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hxx> +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/MP.hxx> +#include <CFKit/Property.hxx> + +///! BUGS: 0 + +///! @file MP.cxx +///! @brief This file handles multi processing in the kernel. +///! @brief Multi processing is needed for multi-tasking operations. + +namespace Kernel +{ + STATIC Property cSMPCoreName; + + ///! A HardwareThread class takes care of it's owned hardware thread. + ///! It has a stack for it's core. + + ///! @brief C++ constructor. + HardwareThread::HardwareThread() = default; + + ///! @brief C++ destructor. + HardwareThread::~HardwareThread() = default; + + //! @brief returns the id of the thread. + const ThreadID& HardwareThread::ID() noexcept + { + return fID; + } + + //! @brief returns the kind of thread we have. + const ThreadKind& HardwareThread::Kind() noexcept + { + return fKind; + } + + //! @brief is the thread busy? + 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) + mp_hang_thread(fStack); + else + mp_wakeup_thread(fStack); + } + + EXTERN Bool rt_check_stack(HAL::StackFramePtr stackPtr); + + /// @brief Switch to hardware thread. + /// @param stack the new hardware thread. + /// @retval true stack was changed, code is running. + /// @retval false stack is invalid, previous code is running. + Bool HardwareThread::Switch(HAL::StackFramePtr stack) + { + if (!rt_check_stack(stack)) + { + /// provide 'nullptr' to free the stack frame. + if (stack == nullptr) + { + delete fStack; + fStack = nullptr; + + return true; + } + + return false; + } + + if (fStack) + { + delete fStack; + fStack = nullptr; + } + + 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. + HardwareThreadScheduler::HardwareThreadScheduler() + { + StringView strCoreName(512); + strCoreName += "\\Class\\Smp\\MPClass"; + + cSMPCoreName.GetKey() = strCoreName; + cSMPCoreName.GetValue() = (UIntPtr)this; + + kcout << "newoskrnl: initializing " << strCoreName.CData() << endl; + } + + ///! @brief Default destructor. + HardwareThreadScheduler::~HardwareThreadScheduler() = default; + + /// @brief Shared singleton function + Ref<HardwareThreadScheduler> HardwareThreadScheduler::The() + { + static HardwareThreadScheduler manager; + return {manager}; + } + + /// @brief Get Stack Frame of Core + HAL::StackFramePtr HardwareThreadScheduler::Leak() noexcept + { + if (fThreadList[fCurrentThread].Leak() && + ProcessHelper::TheCurrentPID() == + fThreadList[fCurrentThread].Leak().Leak()->fSourcePID) + return fThreadList[fCurrentThread].Leak().Leak()->fStack; + + return nullptr; + } + + /// @brief Finds and switch to a free core. + bool HardwareThreadScheduler::Switch(HAL::StackFramePtr stack) + { + if (stack == nullptr) + return false; + + for (SizeT idx = 0; idx < cMaxHWThreads; ++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->SP == 0) + continue; + if (fThreadList[idx].Leak().Leak()->fStack->BP == 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()->Switch(fThreadList[idx].Leak().Leak()->fStack); + + fThreadList[idx].Leak().Leak()->fSourcePID = ProcessHelper::TheCurrentPID(); + + 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*> HardwareThreadScheduler::operator[](const SizeT& idx) + { + if (idx == 0) + { + if (fThreadList[idx].Leak().Leak()->Kind() != kHartSystemReserved) + { + fThreadList[idx].Leak().Leak()->fKind = kHartBoot; + } + } + else if (idx >= cMaxHWThreads) + { + static HardwareThread* fakeThread = new HardwareThread(); + + if (!fakeThread) + { + fakeThread = new HardwareThread(); + } + + fakeThread->fKind = kInvalidHart; + + return {fakeThread}; + } + + return fThreadList[idx].Leak(); + } + + /** + * Check if thread pool isn't empty. + * @return + */ + HardwareThreadScheduler::operator bool() noexcept + { + return !fThreadList.Empty(); + } + + /** + * Reverse operator bool + * @return + */ + bool HardwareThreadScheduler::operator!() noexcept + { + return fThreadList.Empty(); + } + + /// @brief Returns the amount of core present. + /// @return the number of cores. + SizeT HardwareThreadScheduler::Count() noexcept + { + return fThreadList.Count(); + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/MutableArray.cxx b/dev/ZKA/Sources/MutableArray.cxx new file mode 100644 index 00000000..766cb304 --- /dev/null +++ b/dev/ZKA/Sources/MutableArray.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/MutableArray.hxx> diff --git a/dev/ZKA/Sources/Network/IP.cxx b/dev/ZKA/Sources/Network/IP.cxx new file mode 100644 index 00000000..3e5462a1 --- /dev/null +++ b/dev/ZKA/Sources/Network/IP.cxx @@ -0,0 +1,126 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NetworkKit/IP.hxx> +#include <NewKit/Utils.hxx> + +namespace Kernel +{ + 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 Kernel diff --git a/dev/ZKA/Sources/Network/IPC.cxx b/dev/ZKA/Sources/Network/IPC.cxx new file mode 100644 index 00000000..f703e650 --- /dev/null +++ b/dev/ZKA/Sources/Network/IPC.cxx @@ -0,0 +1,68 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NetworkKit/IPC.hxx> +#include <KernelKit/LPC.hxx> +#include <KernelKit/ProcessScheduler.hxx> + +using namespace Kernel; + +/// @internal +/// @brief The internal sanitize function. +Bool ipc_int_sanitize_packet(IPC_MESSAGE_STRUCT* pckt) +{ + auto endian = DEDUCE_ENDIAN(pckt, ((char*)pckt)[0]); + + switch (endian) + { + case Endian::kEndianBig: { + if (pckt->IpcEndianess == eIPCEPLittleEndian) + goto ipc_check_failed; + + break; + } + case Endian::kEndianLittle: { + if (pckt->IpcEndianess == eIPCEPBigEndian) + goto ipc_check_failed; + + break; + } + case Endian::kEndianMixed: + break; + default: + goto ipc_check_failed; + } + + if (pckt->IpcFrom == pckt->IpcTo || + pckt->IpcPacketSize > cIPCEPMsgSize) + { + goto ipc_check_failed; + } + + return pckt->IpcPacketSize > 1 && pckt->IpcHeaderMagic == cRemoteHeaderMagic; + +ipc_check_failed: + ErrLocal() = kErrorIPC; + return false; +} + +namespace Kernel +{ + /// @brief Sanitize packet function + /// @retval true packet is correct. + /// @retval false packet is incorrect and process has crashed. + Bool ipc_sanitize_packet(IPC_MESSAGE_STRUCT* pckt) + { + if (!pckt || + !ipc_int_sanitize_packet(pckt)) + { + ProcessScheduler::The().Leak().TheCurrent().Leak().Crash(); + return false; + } + + return true; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/Network/NetworkDevice.cxx b/dev/ZKA/Sources/Network/NetworkDevice.cxx new file mode 100644 index 00000000..1bcd9e24 --- /dev/null +++ b/dev/ZKA/Sources/Network/NetworkDevice.cxx @@ -0,0 +1,35 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NetworkKit/NetworkDevice.hxx> +#include <NewKit/Utils.hxx> + +namespace Kernel +{ + /// \brief Getter for fNetworkName. + const char* NetworkDevice::Name() const + { + return this->fNetworkName; + } + + /// \brief Setter for fNetworkName. + Boolean NetworkDevice::Name(const char* strView) + { + if (strView == nullptr) + return false; + + if (*strView == 0) + return false; + + if (rt_string_len(strView) > cNetworkNameLen) + return false; + + rt_copy_memory((VoidPtr)strView, + (VoidPtr)this->fNetworkName, rt_string_len(strView)); + + return true; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/New+Delete.cxx b/dev/ZKA/Sources/New+Delete.cxx new file mode 100644 index 00000000..12ea38a7 --- /dev/null +++ b/dev/ZKA/Sources/New+Delete.cxx @@ -0,0 +1,50 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/Heap.hxx> +#include <NewKit/New.hxx> + +void* operator new[](size_t sz) +{ + if (sz == 0) + ++sz; + + return Kernel::mm_new_ke_heap(sz, true, false); +} + +void* operator new(size_t sz) +{ + if (sz == 0) + ++sz; + + return Kernel::mm_new_ke_heap(sz, true, false); +} + +void operator delete[](void* ptr) +{ + if (ptr == nullptr) + return; + + Kernel::mm_delete_ke_heap(ptr); +} + +void operator delete(void* ptr) +{ + if (ptr == nullptr) + return; + + Kernel::mm_delete_ke_heap(ptr); +} + +void operator delete(void* ptr, size_t sz) +{ + if (ptr == nullptr) + return; + + NEWOS_UNUSED(sz); + + Kernel::mm_delete_ke_heap(ptr); +} diff --git a/dev/ZKA/Sources/NewFS+FileManager.cxx b/dev/ZKA/Sources/NewFS+FileManager.cxx new file mode 100644 index 00000000..f94831cd --- /dev/null +++ b/dev/ZKA/Sources/NewFS+FileManager.cxx @@ -0,0 +1,100 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/FileManager.hxx> +#include <KernelKit/Heap.hxx> + +#ifdef __FSKIT_USE_NEWFS__ + +/// @brief NewFS File manager. +/// BUGS: 0 + +namespace Kernel +{ + /// @brief C++ constructor + NewFilesystemManager::NewFilesystemManager() + { + MUST_PASS(Detail::fs_init_newfs()); + fImpl = new NewFSParser(); + + kcout << "newoskrnl: We are done here... (NewFilesystemManager).\r"; + } + + NewFilesystemManager::~NewFilesystemManager() + { + kcout << "newoskrnl: Destroying it...\r"; + + 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; + } + + /// @brief Gets the metafile character. + /// @return + const char NewFilesystemHelper::MetaFile() + { + return kNewFSMetaFilePrefix; + } +} // namespace Kernel + +#endif // ifdef __FSKIT_USE_NEWFS__ diff --git a/dev/ZKA/Sources/NewFS+IO.cxx b/dev/ZKA/Sources/NewFS+IO.cxx new file mode 100644 index 00000000..ddcecde4 --- /dev/null +++ b/dev/ZKA/Sources/NewFS+IO.cxx @@ -0,0 +1,101 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DriveManager.hxx> +#include <KernelKit/FileManager.hxx> + +/************************************************************* + * + * File: NewFS+IO.cxx + * Purpose: Filesystem to mountpoint interface. + * Date: 3/26/24 + * + * Copyright ZKA Technologies., all rights reserved. + * + *************************************************************/ + +#ifdef __FSKIT_USE_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 Kernel; + +/// @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_USE_NEWFS__ diff --git a/dev/ZKA/Sources/NewFS+Journal.cxx b/dev/ZKA/Sources/NewFS+Journal.cxx new file mode 100644 index 00000000..6504b2bc --- /dev/null +++ b/dev/ZKA/Sources/NewFS+Journal.cxx @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hxx> +#include <KernelKit/FileManager.hxx> + +#ifdef __FSKIT_USE_NEWFS__ + +///! BUGS: 0 +///! @file NewFS+Journal.cxx +///! @brief Journaling for NewFS. + +namespace Kernel::Journal +{ +} // namespace Kernel::Journal + +using namespace Kernel; + +#endif // ifdef __FSKIT_USE_NEWFS__ diff --git a/dev/ZKA/Sources/OwnPtr.cxx b/dev/ZKA/Sources/OwnPtr.cxx new file mode 100644 index 00000000..8b0442a7 --- /dev/null +++ b/dev/ZKA/Sources/OwnPtr.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/OwnPtr.hxx> diff --git a/dev/ZKA/Sources/PEFCodeManager.cxx b/dev/ZKA/Sources/PEFCodeManager.cxx new file mode 100644 index 00000000..d557cc2f --- /dev/null +++ b/dev/ZKA/Sources/PEFCodeManager.cxx @@ -0,0 +1,241 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hxx> +#include <KernelKit/Heap.hxx> +#include <KernelKit/PEFCodeManager.hxx> +#include <KernelKit/ProcessScheduler.hxx> +#include <NewKit/Defines.hxx> +#include <NewKit/KernelCheck.hxx> +#include <NewKit/OwnPtr.hxx> +#include <NewKit/String.hxx> + +namespace Kernel +{ + namespace Detail + { + /// @brief Get the PEF platform signature according to the compiled backebnd + UInt32 rt_get_pef_platform(void) noexcept + { +#ifdef __NEWOS_32X0__ + return kPefArch32x0; +#elif defined(__NEWOS_64X0__) + return kPefArch64x0; +#elif defined(__NEWOS_AMD64__) + return kPefArchAMD64; +#elif defined(__NEWOS_PPC64__) + return kPefArchPowerPC; +#elif defined(__NEWOS_ARM64__) + return kPefArchARM64; +#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) + { + fFile.New(const_cast<Char*>(path), cRestrictRB); + + if (StringBuilder::Equals(fFile->MIME(), this->MIME())) + { + fPath = StringBuilder::Construct(path).Leak(); + + auto cPefHeader = "PEFContainer"; + + fCachedBlob = fFile->Read(cPefHeader); + + 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; + + mm_delete_ke_heap(fCachedBlob); + + fCachedBlob = nullptr; + } + } + + /// @brief PEF destructor. + PEFLoader::~PEFLoader() + { + if (fCachedBlob) + mm_delete_ke_heap(fCachedBlob); + + fFile.Delete(); + } + + VoidPtr PEFLoader::FindSymbol(const char* name, Int32 kind) + { + if (!fCachedBlob || fBad) + return nullptr; + + PEFContainer* container = reinterpret_cast<PEFContainer*>(fCachedBlob); + + StringView cPefHeaderStr = StringBuilder::Construct("PEFContainerHeader:").Leak().Leak(); + cPefHeaderStr += name; + + auto blob = fFile->Read(cPefHeaderStr.CData()); + + PEFCommandHeader* container_header = reinterpret_cast<PEFCommandHeader*>(blob); + + 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) + { + mm_delete_ke_heap(blob); + return nullptr; + } + } + + Char* blobRet = new Char[container_header->Size]; + + rt_copy_memory((VoidPtr)((Char*)blob + sizeof(PEFCommandHeader)), blobRet, container_header->Size); + + mm_delete_ke_heap(blob); + return blobRet; + } + } + } + + mm_delete_ke_heap(blob); + return nullptr; + } + + /// @brief Finds the executable entrypoint. + /// @return + ErrorOr<VoidPtr> PEFLoader::FindStart() + { + if (auto sym = this->FindSymbol(kPefStart, kPefCode); sym) + return ErrorOr<VoidPtr>(sym); + + return ErrorOr<VoidPtr>(kErrorExecutable); + } + + /// @brief Tells if the executable is loaded or not. + /// @return + bool PEFLoader::IsLoaded() noexcept + { + return !fBad && fCachedBlob; + } + + namespace Utils + { + bool execute_from_image(PEFLoader& exec, const Int32& procKind) noexcept + { + auto errOrStart = exec.FindStart(); + + if (errOrStart.Error() != 0) + return false; + + PROCESS_HEADER_BLOCK proc(errOrStart.Leak().Leak()); + Ref<PROCESS_HEADER_BLOCK> refProc = proc; + + proc.Kind = procKind; + + return ProcessScheduler::The().Leak().Add(refProc); + } + } // namespace Utils + + const char* PEFLoader::Path() + { + return fPath.Leak().CData(); + } + + const char* PEFLoader::AsString() + { +#ifdef __32x0__ + return "32x0 PEF format."; +#elif defined(__64x0__) + return "64x0 PEF format."; +#elif defined(__x86_64__) + return "x86_64 PEF format."; +#elif defined(__powerpc64__) + return "POWER PEF format."; +#else + return "Unknown PEF format."; +#endif // __32x0__ || __64x0__ || __x86_64__ || __powerpc64__ + } + + const char* PEFLoader::MIME() + { + return kPefApplicationMime; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/PEFSharedObject.cxx b/dev/ZKA/Sources/PEFSharedObject.cxx new file mode 100644 index 00000000..22890e22 --- /dev/null +++ b/dev/ZKA/Sources/PEFSharedObject.cxx @@ -0,0 +1,110 @@ +/* + * ======================================================== + * + * Kernel + * Copyright ZKA Technologies., all rights reserved. + * + * ======================================================== + */ + +#include <KernelKit/DebugOutput.hxx> +#include <KernelKit/PEF.hxx> +#include <KernelKit/PEFSharedObject.hxx> +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/ThreadLocalStorage.hxx> +#include <NewKit/Defines.hxx> + +/* ------------------------------------------- + + Revision History: + + 01/02/24: Rework shared sharedObj ABI, except a rtl_init_shared_object and + rtl_fini_shared_object (amlel) 15/02/24: Breaking changes, changed the name of the + routines. (amlel) + + 07/28/24: Replace rt_library_free with rtl_fini_shared_object + + ------------------------------------------- */ + +using namespace Kernel; + +/***********************************************************************************/ +/// @file PEFSharedObjectRT.cxx +/// @brief PEF's shared object runtime. +/***********************************************************************************/ + +/***********************************************************************************/ +/** @brief Library initializer. */ +/***********************************************************************************/ + +EXTERN_C SharedObjectPtr rtl_init_shared_object(PROCESS_HEADER_BLOCK* header) +{ + SharedObjectPtr sharedObj = tls_new_class<PEFSharedObjectInterface>(); + + if (!sharedObj) + { + header->Crash(); + + return nullptr; + } + + sharedObj->Mount(tls_new_class<PEFSharedObjectInterface::PEF_SHARED_OBJECT_TRAITS>()); + + if (!sharedObj->Get()) + { + header->Crash(); + + return nullptr; + } + + sharedObj->Get()->fImageObject = + header->Image; + + if (!sharedObj->Get()->fImageObject) + { + header->Crash(); + + return nullptr; + } + + sharedObj->Get()->fImageEntrypointOffset = + sharedObj->Load<VoidPtr>(kPefStart, rt_string_len(kPefStart, 0), kPefCode); + + return sharedObj; +} + +/***********************************************************************************/ +/** @brief Frees the sharedObj. */ +/** @note Please check if the lib got freed! */ +/** @param lib The sharedObj to free. */ +/** @param successful Reports if successful or not. */ +/***********************************************************************************/ + +EXTERN_C Void rtl_fini_shared_object(PROCESS_HEADER_BLOCK* header, SharedObjectPtr lib, Bool* successful) +{ + MUST_PASS(successful); + + // sanity check (will also trigger a bug check if this fails) + if (lib == nullptr) + { + *successful = false; + header->Crash(); + } + + delete lib->Get(); + delete lib; + + lib = nullptr; + + *successful = true; +} + +/***********************************************************************************/ +/// @brief Unimplemented function (crashes by default) +/// @param +/***********************************************************************************/ + +EXTERN_C void __mh_purecall(void) +{ + kcout << "newoskrnl: unimplemented symbol!\r"; +} diff --git a/dev/ZKA/Sources/PRDT.cxx b/dev/ZKA/Sources/PRDT.cxx new file mode 100644 index 00000000..f9bbd685 --- /dev/null +++ b/dev/ZKA/Sources/PRDT.cxx @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/String.hxx> +#include <StorageKit/PRDT.hxx> + +namespace Kernel +{ + /// @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 Kernel diff --git a/dev/ZKA/Sources/PageAllocator.cxx b/dev/ZKA/Sources/PageAllocator.cxx new file mode 100644 index 00000000..4f64b05f --- /dev/null +++ b/dev/ZKA/Sources/PageAllocator.cxx @@ -0,0 +1,55 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hxx> +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/PageAllocator.hxx> + +/// @brief Internal namespace, used internally by kernel. +namespace Kernel::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) + { +#ifdef __NEWOS_SUPPORT_NX__ + PTE* VirtualAddrTable = reinterpret_cast<PTE*>(VirtualAddr); + + MUST_PASS(!VirtualAddrTable->ExecDisable == false); + VirtualAddrTable->ExecDisable = true; + + hal_flush_tlb(); +#endif // ifdef __NEWOS_SUPPORT_NX__ + } + + bool page_disable(UIntPtr VirtualAddr) + { + if (VirtualAddr) + { + auto VirtualAddrTable = (PTE*)(VirtualAddr); + + MUST_PASS(!VirtualAddrTable->Present == true); + VirtualAddrTable->Present = false; + + hal_flush_tlb(); + + return true; + } + + return false; + } +} // namespace Kernel::Detail diff --git a/dev/ZKA/Sources/PageManager.cxx b/dev/ZKA/Sources/PageManager.cxx new file mode 100644 index 00000000..7e0ef67b --- /dev/null +++ b/dev/ZKA/Sources/PageManager.cxx @@ -0,0 +1,126 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/PageManager.hxx> + +#ifdef __NEWOS_AMD64__ +#include <HALKit/AMD64/HalPageAlloc.hxx> +#elif defined(__NEWOS_ARM64__) +#include <HALKit/ARM64/HalPageAlloc.hxx> +#endif // ifdef __NEWOS_AMD64__ || defined(__NEWOS_ARM64__) + +//! null deref will throw (Page Zero detected, aborting app!) +#define kProtectedRegionEnd (512) + +namespace Kernel +{ + PTEWrapper::PTEWrapper(Boolean Rw, Boolean User, Boolean ExecDisable, UIntPtr VirtAddr) + : fRw(Rw), + fUser(User), + fExecDisable(ExecDisable), + fVirtAddr(VirtAddr), + fCache(false), + fShareable(false), + fWt(false), + fPresent(true), + fAccessed(false) + { + } + + PTEWrapper::~PTEWrapper() = default; + + /// @brief Flush virtual address. + /// @param VirtAddr + Void 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) + { + kcout << "newoskrnl: Allocating VMH page from PageManager...\r"; + + // Store PTE wrapper right after PTE. + VoidPtr ptr = Kernel::HAL::hal_alloc_page(Rw, User, Sz); + + if (ptr == kBadAddress) + { + kcout << "[create_page_wrapper] kBadAddress returned\n"; + ke_stop(RUNTIME_CHECK_POINTER); + } + + 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 Kernel diff --git a/dev/ZKA/Sources/Pmm.cxx b/dev/ZKA/Sources/Pmm.cxx new file mode 100644 index 00000000..4a511c30 --- /dev/null +++ b/dev/ZKA/Sources/Pmm.cxx @@ -0,0 +1,96 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/Pmm.hxx> + +#if defined(__NEWOS_ARM64__) +#include <HALKit/ARM64/Processor.hxx> +#endif // defined(__NEWOS_ARM64__) + +#if defined(__NEWOS_AMD64__) +#include <HALKit/AMD64/Processor.hxx> +#endif // defined(__NEWOS_AMD64__) + +namespace Kernel +{ + /// @brief Pmm constructor. + Pmm::Pmm() + : fPageManager() + { + kcout << "[PMM] Allocate PageMemoryManager"; + } + + Pmm::~Pmm() = default; + + /* If this returns Null pointer, enter emergency mode */ + /// @param user is this a user page? + /// @param readWrite is it r/w? + Ref<PTEWrapper> Pmm::RequestPage(Boolean user, Boolean readWrite) + { + PTEWrapper pt = fPageManager.Leak().Request(user, readWrite, false, kPTESize); + + if (pt.fPresent) + { + kcout << "[PMM]: Allocation was successful.\r"; + return Ref<PTEWrapper>(pt); + } + + kcout << "[PMM]: Allocation failed.\r"; + + 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 Kernel diff --git a/dev/ZKA/Sources/ProcessHeap.cxx b/dev/ZKA/Sources/ProcessHeap.cxx new file mode 100644 index 00000000..d501f31d --- /dev/null +++ b/dev/ZKA/Sources/ProcessHeap.cxx @@ -0,0 +1,277 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/ProcessHeap.hxx> +#include <NewKit/PageManager.hxx> + +#define cHeapHeaderPaddingSz (16U) + +/// @file ProcessHeap.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 Kernel +{ + /** + * @brief Process Heap Header + * @note Allocated per process, it denotes the user's heap. + */ + struct PROCESS_HEAP_HEADER final + { + UInt32 fPageMagic; + Int32 fPageFlags; + Boolean fPageFree; + UIntPtr fPageVirtStart; + SizeT fPageVirtSize; + UInt8 fPagePad[cHeapHeaderPaddingSz]; + }; + + /// @brief PROCESS_HEAP_HEADER as pointer type. + typedef PROCESS_HEAP_HEADER* PROCESS_HEAP_HEADER_PTR; + + /** + * @brief Process heap 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 ProcessHeapHelper final + { + ProcessHeapHelper() = delete; + + public: + ~ProcessHeapHelper() = default; + + public: + STATIC SizeT& Count() noexcept + { + return s_NumPools; + } + + STATIC Ref<Pmm>& Leak() noexcept + { + return s_Pmm; + } + + STATIC Boolean& IsEnabled() noexcept + { + return s_PoolsAreEnabled; + } + + STATIC MutableArray<Ref<PTEWrapper>>& The() noexcept + { + 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 ProcessHeapHelper::s_NumPools = 0UL; + Ref<Pmm> ProcessHeapHelper::s_Pmm; + Boolean ProcessHeapHelper::s_PoolsAreEnabled = true; + MutableArray<Ref<PTEWrapper>> ProcessHeapHelper::s_Pool; + + STATIC VoidPtr sched_find_unused_heap(Int32 flags, SizeT len); + STATIC Void sched_free_heap_internal(VoidPtr vaddr); + STATIC VoidPtr sched_make_heap_internal(VoidPtr vaddr, Int32 flags, SizeT len); + STATIC Boolean sched_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 sched_find_unused_heap(Int32 flags, SizeT len) + { + SizeT index = 0UL; + + while (true) + { + /* ************************************ */ + /* allocate if it doesnt exist. */ + /* ************************************ */ + if (!ProcessHeapHelper::The()[index]) + { + ProcessHeapHelper::The().Add(Kernel::Ref<Kernel::PTEWrapper>()); + } + + if (ProcessHeapHelper::The()[index] && + !ProcessHeapHelper::The()[index].Leak().Leak().Present()) + { + ProcessHeapHelper::Leak().Leak().TogglePresent( + ProcessHeapHelper::The()[index].Leak().Leak(), true); + + ProcessHeapHelper::Leak().Leak().ToggleUser( + ProcessHeapHelper::The()[index].Leak().Leak(), true); + + kcout << "[sched_find_unused_heap] Done, trying to make a pool now...\r"; + + return sched_make_heap_internal( + (VoidPtr)ProcessHeapHelper::The()[index].Leak().Leak().VirtualAddress(), + flags, len); + } + + ++index; + } + + return nullptr; + } + + /// @brief Makes a new heap for the process to use. + /// @param virtual_address the virtual address of the process. + /// @param flags the flags. + /// @return + STATIC VoidPtr sched_make_heap_internal(VoidPtr virtual_address, Int32 flags, SizeT len_in_gb) + { + if (virtual_address) + { + PROCESS_HEAP_HEADER* process_heap_hdr = reinterpret_cast<PROCESS_HEAP_HEADER*>(virtual_address); + + if (!process_heap_hdr->fPageFree) + { + kcout + << "[sched_make_heap_internal] process_heap_hdr->fPageFree, HeapPtr already exists\n"; + return nullptr; + } + + process_heap_hdr->fPageFlags = flags; + process_heap_hdr->fPageMagic = kProcessHeapMag; + process_heap_hdr->fPageFree = false; + process_heap_hdr->fPageVirtStart = (UIntPtr)virtual_address + sizeof(PROCESS_HEAP_HEADER); + process_heap_hdr->fPageVirtSize = len_in_gb; + + kcout << "[sched_make_heap_internal] New allocation has been done, returning new chunk.\n"; + + return reinterpret_cast<VoidPtr>( + (reinterpret_cast<UIntPtr>(virtual_address) + sizeof(PROCESS_HEAP_HEADER))); + } + + kcout << "[sched_make_heap_internal] Address is invalid"; + return nullptr; + } + + /// @brief Internally makrs the heap as free. + /// This is done by setting the fPageFree bit to true + /// @param virtual_address + /// @return + STATIC Void sched_free_heap_internal(VoidPtr virtual_address) + { + PROCESS_HEAP_HEADER* process_heap_hdr = reinterpret_cast<PROCESS_HEAP_HEADER*>( + reinterpret_cast<UIntPtr>(virtual_address) - sizeof(PROCESS_HEAP_HEADER)); + + if (process_heap_hdr->fPageMagic == kProcessHeapMag) + { + if (!process_heap_hdr->fPageFree) + { + ProcessScheduler::The().Leak().TheCurrent().Leak().Crash(); + return; + } + + process_heap_hdr->fPageFree = true; + process_heap_hdr->fPageFlags = 0; + + kcout << "[sched_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 sched_check_and_free_heap(const SizeT& index, VoidPtr ptr) + { + if (ProcessHeapHelper::The()[index]) + { + // ErrorOr<>::operator Boolean + /// if (address matches) + /// -> Free heap. + if (ProcessHeapHelper::The()[index].Leak().Leak().VirtualAddress() == + (UIntPtr)ptr) + { + ProcessHeapHelper::Leak().Leak().FreePage( + ProcessHeapHelper::The()[index].Leak().Leak()); + + --ProcessHeapHelper::Count(); + + sched_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 sched_new_heap(Int32 flags, SizeT page_size) + { + if (!ProcessHeapHelper::IsEnabled()) + return nullptr; + + if (VoidPtr ret = sched_find_unused_heap(flags, page_size)) + return ret; + + // this wasn't set to true + auto ref_page = ProcessHeapHelper::Leak().Leak().RequestPage( + ((flags & kProcessHeapUser)), (flags & kProcessHeapRw)); + + if (ref_page) + { + ///! reserve page. + ProcessHeapHelper::The()[ProcessHeapHelper::Count()].Leak() = ref_page; + auto& ref = ProcessHeapHelper::Count(); + + ++ref; // increment the number of addresses we have now. + + // finally make the pool address. + return sched_make_heap_internal( + reinterpret_cast<VoidPtr>(ref_page.Leak().VirtualAddress()), flags, page_size); + } + + return nullptr; + } + + /// @brief free a pool pointer. + /// @param ptr The pool pointer to free. + /// @return status code + Int32 sched_free_heap(VoidPtr ptr) + { + if (!ProcessHeapHelper::IsEnabled()) + return -1; + + if (ptr) + { + SizeT base = ProcessHeapHelper::Count(); + + if (sched_check_and_free_heap(base, ptr)) + return 0; + + for (SizeT index = 0; index < ProcessHeapHelper::The().Count(); ++index) + { + if (sched_check_and_free_heap(index, ptr)) + return 0; + + --base; + } + } + + return -1; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/ProcessScheduler.cxx b/dev/ZKA/Sources/ProcessScheduler.cxx new file mode 100644 index 00000000..8ca94b60 --- /dev/null +++ b/dev/ZKA/Sources/ProcessScheduler.cxx @@ -0,0 +1,464 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file ProcessScheduler.cxx +/// @brief MicroKernel process scheduler. +/***********************************************************************************/ + +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/PEFSharedObject.hxx> +#include <KernelKit/MP.hxx> +#include <KernelKit/Heap.hxx> +#include <NewKit/String.hxx> +#include <KernelKit/LPC.hxx> + +///! BUGS: 0 + +/***********************************************************************************/ +/* This file handles the process scheduling. */ +/***********************************************************************************/ + +namespace Kernel +{ + /***********************************************************************************/ + /// @brief Exit Code global + /***********************************************************************************/ + + STATIC Int32 cLastExitCode = 0U; + + /// @brief Gets the last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + const Int32& sched_get_exit_code(void) noexcept + { + return cLastExitCode; + } + + /***********************************************************************************/ + /// @brief crash current process. + /***********************************************************************************/ + + void PROCESS_HEADER_BLOCK::Crash() + { + kcout << (*this->Name == 0 ? "Kernel" : this->Name) << ": crashed. (id = "; + kcout << number(kErrorProcessFault); + kcout << ")\r"; + + if (Kernel::ProcessScheduler::The().Leak().CurrentTeam().AsArray().Count() < 1) + { + kcout << "*** BAD PROCESS ***\rTerminating as we are the only process...\r"; + ke_stop(RUNTIME_CHECK_PROCESS); + } + + this->Exit(kErrorProcessFault); + } + + /// @brief Gets the local last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + const Int32& PROCESS_HEADER_BLOCK::GetExitCode() noexcept + { + return this->fLastExitCode; + } + + Int32& PROCESS_HEADER_BLOCK::GetLocalCode() noexcept + { + return fLocalCode; + } + + void PROCESS_HEADER_BLOCK::Wake(const bool should_wakeup) + { + this->Status = + should_wakeup ? ProcessStatus::kRunning : ProcessStatus::kFrozen; + } + + /***********************************************************************************/ + + VoidPtr PROCESS_HEADER_BLOCK::New(const SizeT& sz) + { + if (this->HeapCursor) + { + if (this->FreeMemory < 1) + { + ErrLocal() = kErrorHeapOutOfMemory; + + /* We're going out of memory! crash... */ + this->Crash(); + + return nullptr; + } + + this->HeapCursor = reinterpret_cast<VoidPtr>((UIntPtr)this->HeapCursor + (sizeof(sz))); + VoidPtr ptr = this->HeapCursor; + + ++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& pool_ptr_cur_sz, const SizeT& pool_ptr_used_sz) + { + if (pool == nullptr || + pool_ptr == nullptr) + return false; + + UIntPtr* uint_pool_ptr = (UIntPtr*)pool_ptr; + UIntPtr* uint_pool = (UIntPtr*)pool; + + return (UIntPtr)&uint_pool > (UIntPtr)&uint_pool_ptr && + pool_ptr_cur_sz > pool_ptr_used_sz; + } + + /* @brief free pointer from usage. */ + Boolean PROCESS_HEADER_BLOCK::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->FreeMemory)) + { + 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* PROCESS_HEADER_BLOCK::GetProcessName() noexcept + { + return this->Name; + } + + /// @brief process selector getter. + const ProcessLevelRing& PROCESS_HEADER_BLOCK::GetLevelRing() noexcept + { + return this->Selector; + } + + /// @brief process status getter. + const ProcessStatus& PROCESS_HEADER_BLOCK::GetStatus() noexcept + { + return this->Status; + } + + /***********************************************************************************/ + + /** + @brief Affinity is the time slot allowed for the process. + */ + const AffinityKind& PROCESS_HEADER_BLOCK::GetAffinity() noexcept + { + return this->Affinity; + } + + /** + @brief Standard exit proc. + */ + void PROCESS_HEADER_BLOCK::Exit(const Int32& exit_code) + { + if (this->ProcessId != + ProcessScheduler::The().Leak().TheCurrent().Leak().ProcessId) + ke_stop(RUNTIME_CHECK_PROCESS); + + fLastExitCode = exit_code; + cLastExitCode = exit_code; + + //! Delete image if not done already. + if (this->Image) + mm_delete_ke_heap(this->Image); + + if (this->StackFrame) + mm_delete_ke_heap((VoidPtr)this->StackFrame); + + this->Image = nullptr; + this->StackFrame = nullptr; + + if (this->Kind == kSharedObjectKind) + { + bool success = false; + rtl_fini_shared_object(this, this->DLLPtr, &success); + + if (success) + { + this->DLLPtr = nullptr; + } + } + + ProcessScheduler::The().Leak().Remove(this->ProcessId); + } + + /// @brief Add process to list. + /// @param process + /// @return + SizeT ProcessScheduler::Add(Ref<PROCESS_HEADER_BLOCK>& process) + { + if (!process.Leak().Image) + { + if (process.Leak().Kind != PROCESS_HEADER_BLOCK::kSharedObjectKind) + { + return -kErrorNoEntrypoint; + } + } + + if (mTeam.AsArray().Count() > kSchedProcessLimitPerTeam) + return -kErrorOutOfTeamSlot; + + kcout << "ProcessScheduler:: adding process to team...\r"; + + // Create heap according to type of process. + if (process.Leak().Kind == PROCESS_HEADER_BLOCK::kAppKind) + { + process.Leak().HeapPtr = sched_new_heap(kProcessHeapUser | kProcessHeapRw, process.Leak().SizeMemory); + } + else if (process.Leak().Kind == PROCESS_HEADER_BLOCK::kSharedObjectKind) + { + process.Leak().DLLPtr = rtl_init_shared_object(&process.Leak()); + process.Leak().HeapPtr = sched_new_heap(kProcessHeapUser | kProcessHeapRw | kProcessHeapShared, process.Leak().SizeMemory); + } + else + { + // Something went wrong, do not continue, process may be incorrect. + process.Leak().Crash(); + return -kErrorProcessFault; + } + + process.Leak().StackFrame = reinterpret_cast<HAL::StackFrame*>( + mm_new_ke_heap(sizeof(HAL::StackFrame), Yes, Yes)); + + MUST_PASS(process.Leak().StackFrame); + + if (process.Leak().Image) + { + process.Leak().StackFrame->BP = reinterpret_cast<HAL::Reg>(process.Leak().Image); + } + else + { + if (process.Leak().Kind != PROCESS_HEADER_BLOCK::kSharedObjectKind) + { + process.Leak().Crash(); + return -kErrorProcessFault; + } + } + + if (!process.Leak().StackFrame->SP) + process.Leak().StackFrame->SP = reinterpret_cast<HAL::Reg>(mm_new_ke_heap(sizeof(UInt8) * 8196, Yes, Yes)); + + process.Leak().Status = ProcessStatus::kStarting; + + process.Leak().ProcessId = (mTeam.AsArray().Count() - 1); + process.Leak().HeapCursor = process.Leak().HeapPtr; + + MUST_PASS(mTeam.AsArray().Add(process)); + + return (mTeam.AsArray().Count() - 1); + } + + /// @brief Remove process from list. + /// @param processSlot process slot inside team. + /// @retval true process was removed. + /// @retval false process doesn't exist in team. + Bool ProcessScheduler::Remove(SizeT processSlot) + { + // check if process is within range. + if (processSlot > mTeam.AsArray().Count()) + return false; + + // also check if the process isn't a dummy one. + if (mTeam.AsArray()[processSlot].Leak().Leak().Image == nullptr) + return false; + + kcout << "ProcessScheduler: removing process\r"; + + return mTeam.AsArray().Remove(processSlot); + } + + /// @brief Run scheduler. + /// @return + SizeT ProcessScheduler::Run() noexcept + { + SizeT process_index = 0; //! we store this guy to tell the scheduler how many + //! things we have scheduled. + + for (; process_index < mTeam.AsArray().Count(); ++process_index) + { + auto process = mTeam.AsArray()[process_index]; + + //! check if process needs to be scheduled. + if (ProcessHelper::CanBeScheduled(process.Leak())) + { + auto unwrapped_process = *process.Leak(); + + // set the current process. + mTeam.AsRef() = unwrapped_process; + + // tell helper to find a core to schedule on. + ProcessHelper::Switch(unwrapped_process.StackFrame, + unwrapped_process.ProcessId); + + unwrapped_process.PTime = static_cast<Int32>(unwrapped_process.Affinity); + + kcout << unwrapped_process.Name << ": has been switched to process core.\r"; + } + else + { + // otherwise increment the P-time. + --mTeam.AsRef().Leak().PTime; + } + } + + return process_index; + } + + /// @brief Gets the current scheduled team. + /// @return + ProcessTeam& ProcessScheduler::CurrentTeam() + { + return mTeam; + } + + /// @internal + STATIC Ref<ProcessScheduler> cSchedulerRef; + + /// @brief Shared instance of the process scheduler. + /// @return + Ref<ProcessScheduler>& ProcessScheduler::The() + { + return cSchedulerRef; + } + + /// @brief Gets current running process. + /// @return + Ref<PROCESS_HEADER_BLOCK>& ProcessScheduler::TheCurrent() + { + return mTeam.AsRef(); + } + + /// @brief Current proccess id getter. + /// @return Process ID integer. + PID& ProcessHelper::TheCurrentPID() + { + kcout << "ProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; + return ProcessScheduler::The().Leak().TheCurrent().Leak().ProcessId; + } + + /// @brief Check if process can be schedulded. + /// @param process the process reference. + /// @retval true can be schedulded. + /// @retval false cannot be schedulded. + bool ProcessHelper::CanBeScheduled(Ref<PROCESS_HEADER_BLOCK>& process) + { + if (process.Leak().Status == ProcessStatus::kFrozen || + process.Leak().Status == ProcessStatus::kDead) + return false; + + if (process.Leak().Kind == PROCESS_HEADER_BLOCK::kSharedObjectKind) + { + if (auto start = process.Leak().DLLPtr->Load<VoidPtr>(kPefStart, rt_string_len(kPefStart), kPefCode); + start) + { + process.Leak().Image = start; + process.Leak().StackFrame->BP = reinterpret_cast<HAL::Reg>(start); + } + } + + if (process.Leak().GetStatus() == ProcessStatus::kStarting) + { + if (process.Leak().PTime <= 0) + { + process.Leak().Status = ProcessStatus::kRunning; + process.Leak().Affinity = AffinityKind::kStandard; + + return true; + } + + ++process.Leak().PTime; + } + + return process.Leak().PTime > 0; + } + + /** + * @brief Spin scheduler class. + */ + + SizeT ProcessHelper::StartScheduling() + { + auto& process_ref = ProcessScheduler::The().Leak(); + SizeT ret = process_ref.Run(); + + return ret; + } + + /** + * \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 < HardwareThreadScheduler::The().Leak().Count(); ++index) + { + if (HardwareThreadScheduler::The().Leak()[index].Leak()->Kind() == kInvalidHart) + continue; + + if (HardwareThreadScheduler::The().Leak()[index].Leak()->StackFrame() == the_stack) + { + HardwareThreadScheduler::The().Leak()[index].Leak()->Busy(false); + continue; + } + + if (HardwareThreadScheduler::The().Leak()[index].Leak()->IsBusy()) + continue; + + if (HardwareThreadScheduler::The().Leak()[index].Leak()->Kind() != + ThreadKind::kHartBoot && + HardwareThreadScheduler::The().Leak()[index].Leak()->Kind() != + ThreadKind::kHartSystemReserved) + { + HardwareThreadScheduler::The().Leak()[index].Leak()->Busy(true); + ProcessHelper::TheCurrentPID() = new_pid; + + return HardwareThreadScheduler::The().Leak()[index].Leak()->Switch(the_stack); + } + } + + return false; + } + + /// @brief this checks if any process is on the team. + ProcessScheduler::operator bool() + { + return mTeam.AsArray().Count() > 0; + } + + /// @brief this checks if no process is on the team. + bool ProcessScheduler::operator!() + { + return mTeam.AsArray().Count() == 0; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/ProcessTeam.cxx b/dev/ZKA/Sources/ProcessTeam.cxx new file mode 100644 index 00000000..81307d97 --- /dev/null +++ b/dev/ZKA/Sources/ProcessTeam.cxx @@ -0,0 +1,38 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file ProcessTeam.cxx +/// @brief Process teams implementation. +/***********************************************************************************/ + +#include <KernelKit/ProcessScheduler.hxx> + +namespace Kernel +{ + /// @brief Process list array getter. + /// @return The list of process to schedule. + MutableArray<Ref<PROCESS_HEADER_BLOCK>>& ProcessTeam::AsArray() + { + return mProcessList; + } + + /// @brief Get team ID. + /// @return The team's ID. + UInt64& ProcessTeam::Id() noexcept + { + return mTeamId; + } + + /// @brief Current process getter. + /// @return The current process header. + Ref<PROCESS_HEADER_BLOCK>& ProcessTeam::AsRef() + { + return mCurrentProcess; + } +} // namespace Kernel + +// last rev 05-03-24 diff --git a/dev/ZKA/Sources/Property.cxx b/dev/ZKA/Sources/Property.cxx new file mode 100644 index 00000000..04b4367e --- /dev/null +++ b/dev/ZKA/Sources/Property.cxx @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <CFKit/Property.hxx> + +namespace Kernel +{ + Property::~Property() = default; + + bool Property::StringEquals(StringView& name) + { + return this->fName && this->fName == name; + } + + StringView& Property::GetKey() + { + return this->fName; + } + + PropertyId& Property::GetValue() + { + return fAction; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/Ref.cxx b/dev/ZKA/Sources/Ref.cxx new file mode 100644 index 00000000..cf383271 --- /dev/null +++ b/dev/ZKA/Sources/Ref.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Ref.hxx> diff --git a/dev/ZKA/Sources/Semaphore.cxx b/dev/ZKA/Sources/Semaphore.cxx new file mode 100644 index 00000000..c159240e --- /dev/null +++ b/dev/ZKA/Sources/Semaphore.cxx @@ -0,0 +1,62 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/Semaphore.hxx> + +namespace Kernel +{ + bool Semaphore::Unlock() noexcept + { + if (fLockingProcess) + fLockingProcess = nullptr; + + return fLockingProcess == nullptr; + } + + bool Semaphore::Lock(PROCESS_HEADER_BLOCK* process) + { + if (!process || fLockingProcess) + return false; + + fLockingProcess = process; + + return true; + } + + bool Semaphore::IsLocked() const + { + return fLockingProcess; + } + + bool Semaphore::LockOrWait(PROCESS_HEADER_BLOCK* process, HardwareTimerInterface* timer) + { + if (process == nullptr) + return false; + + if (timer == nullptr) + return false; + + this->Lock(process); + + timer->Wait(); + + return this->Lock(process); + } + + /// @brief Wait with process, either wait for process being invalid, or not being run. + Void Semaphore::WaitForProcess() noexcept + { + while (fLockingProcess) + { + if (fLockingProcess->GetStatus() != ProcessStatus::kRunning) + { + this->Unlock(); + break; + } + } + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/Storage/AHCIDeviceInterface.cxx b/dev/ZKA/Sources/Storage/AHCIDeviceInterface.cxx new file mode 100644 index 00000000..dde33193 --- /dev/null +++ b/dev/ZKA/Sources/Storage/AHCIDeviceInterface.cxx @@ -0,0 +1,35 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <StorageKit/AHCI.hxx> + +using namespace Kernel; + +/// @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/dev/ZKA/Sources/Storage/ATADeviceInterface.cxx b/dev/ZKA/Sources/Storage/ATADeviceInterface.cxx new file mode 100644 index 00000000..1611e790 --- /dev/null +++ b/dev/ZKA/Sources/Storage/ATADeviceInterface.cxx @@ -0,0 +1,88 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <StorageKit/ATA.hxx> + +using namespace Kernel; + +/// @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/dev/ZKA/Sources/Storage/NVMEDeviceInterface.cxx b/dev/ZKA/Sources/Storage/NVMEDeviceInterface.cxx new file mode 100644 index 00000000..7d07bf4b --- /dev/null +++ b/dev/ZKA/Sources/Storage/NVMEDeviceInterface.cxx @@ -0,0 +1,28 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <StorageKit/NVME.hxx> + +namespace Kernel +{ + NVMEDeviceInterface::NVMEDeviceInterface(void (*Out)(MountpointInterface* outpacket), + void (*In)(MountpointInterface* inpacket), + void (*Cleanup)(void)) + : DeviceInterface(Out, In), fCleanup(Cleanup) + { + } + + NVMEDeviceInterface::~NVMEDeviceInterface() + { + if (fCleanup) + fCleanup(); + } + + const char* NVMEDeviceInterface::Name() const + { + return ("NVMEDeviceInterface"); + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/Storage/SCSIDeviceInterface.cxx b/dev/ZKA/Sources/Storage/SCSIDeviceInterface.cxx new file mode 100644 index 00000000..da75a181 --- /dev/null +++ b/dev/ZKA/Sources/Storage/SCSIDeviceInterface.cxx @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#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/dev/ZKA/Sources/Stream.cxx b/dev/ZKA/Sources/Stream.cxx new file mode 100644 index 00000000..3a809a8d --- /dev/null +++ b/dev/ZKA/Sources/Stream.cxx @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + + File: Stream.cxx + Purpose: Stream object + + Revision History: + +------------------------------------------- */ + +#include <NewKit/Stream.hxx> diff --git a/dev/ZKA/Sources/String.cxx b/dev/ZKA/Sources/String.cxx new file mode 100644 index 00000000..8ea7d65f --- /dev/null +++ b/dev/ZKA/Sources/String.cxx @@ -0,0 +1,246 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/String.hxx> +#include <NewKit/Utils.hxx> +#include <KernelKit/DebugOutput.hxx> + +namespace Kernel +{ + Char* StringView::Data() + { + return fData; + } + + const Char* StringView::CData() const + { + return fData; + } + + Size StringView::Length() const + { + return fSz; + } + + 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 rt_string_append(Char* lhs, const Char* rhs, Int32 cur) + { + SizeT sz_rhs = rt_string_len(rhs); + SizeT rhs_i = 0; + + for (; rhs_i < sz_rhs; ++rhs_i) + { + lhs[rhs_i + cur] = rhs[rhs_i]; + } + } + + StringView& StringView::operator+=(const Char* rhs) + { + rt_string_append(this->fData, rhs, this->fCur); + this->fCur += rt_string_len(rhs); + + return *this; + } + + StringView& StringView::operator+=(const StringView& rhs) + { + if (rt_string_len(rhs.fData) > this->Length()) + return *this; + + rt_string_append(this->fData, const_cast<Char*>(rhs.fData), this->fCur); + this->fCur += rt_string_len(const_cast<Char*>(rhs.fData)); + + return *this; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/ThreadLocalStorage.cxx b/dev/ZKA/Sources/ThreadLocalStorage.cxx new file mode 100644 index 00000000..f258fa11 --- /dev/null +++ b/dev/ZKA/Sources/ThreadLocalStorage.cxx @@ -0,0 +1,76 @@ +/* + * ======================================================== + * + * Kernel + * Copyright ZKA Technologies., all rights reserved. + * + * ======================================================== + */ + +#include <NewKit/String.hxx> +#include <CFKit/Property.hxx> +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/ThreadLocalStorage.hxx> + +///! BUGS: 0 + +/***********************************************************************************/ +/// @file ThreadLocalStorage.cxx +/// @brief TLS inside the kernel. +/***********************************************************************************/ + +using namespace Kernel; + +Kernel::Property cTLSEnforceCheck; + +/** + * @brief Checks for cookie inside the TIB. + * @param tib the TIB to check. + * @return if the cookie is enabled. + */ + +Boolean tls_check_tib(THREAD_INFORMATION_BLOCK* the_tib) +{ + if (!the_tib) + return false; + + Encoder encoder; + const char* tibAsBytes = encoder.AsBytes(the_tib); + + kcout << "newoskrnl: checking for a valid cookie inside the TIB...\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 Bool tls_check_syscall_impl(Kernel::VoidPtr tib_ptr) noexcept +{ + if (!tib_ptr) + { + if (cTLSEnforceCheck.GetValue() == No) + { + return true; + } + else + { + kcout << "newoskrnl: failing because of an invalid TIB...\r"; + return false; + } + } + + THREAD_INFORMATION_BLOCK* tib_struct = (THREAD_INFORMATION_BLOCK*)tib_ptr; + + if (!tls_check_tib(tib_struct)) + { + kcout << "newoskrnl: crashing because of an invalid TIB...\r"; + return false; + } + + kcout << "newoskrnl: Verification succeeded! staying alive...\r"; + return true; +} diff --git a/dev/ZKA/Sources/ThreadScheduler.cxx b/dev/ZKA/Sources/ThreadScheduler.cxx new file mode 100644 index 00000000..fb822a68 --- /dev/null +++ b/dev/ZKA/Sources/ThreadScheduler.cxx @@ -0,0 +1,8 @@ +/* -------------------------------------------
+
+ Copyright ZKA Technologies.
+
+------------------------------------------- */
+
+#include <KernelKit/ProcessScheduler.hxx>
+#include <KernelKit/MP.hxx>
\ No newline at end of file diff --git a/dev/ZKA/Sources/Timer.cxx b/dev/ZKA/Sources/Timer.cxx new file mode 100644 index 00000000..041c4b67 --- /dev/null +++ b/dev/ZKA/Sources/Timer.cxx @@ -0,0 +1,44 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <KernelKit/Timer.hxx> + +///! BUGS: 0 +///! @file Timer.cxx + +using namespace Kernel; + +/// @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) +{ + MUST_PASS(fWaitFor > 0); +} + +HardwareTimer::~HardwareTimer() +{ + fWaitFor = 0; +} + +Int32 HardwareTimer::Wait() noexcept +{ + if (fWaitFor < 1) + return -1; + + while (*fDigitalTimer < (*fDigitalTimer + fWaitFor)) + { + ; + } + + return 0; +} diff --git a/dev/ZKA/Sources/URL.cxx b/dev/ZKA/Sources/URL.cxx new file mode 100644 index 00000000..189aba8e --- /dev/null +++ b/dev/ZKA/Sources/URL.cxx @@ -0,0 +1,98 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <CFKit/URL.hxx> +#include <KernelKit/DebugOutput.hxx> +#include <NewKit/Utils.hxx> + +/// BUGS: 0 + +namespace Kernel +{ + URL::URL(StringView& strUrl) + : fUrlView(strUrl, false) + { + } + + URL::~URL() = default; + + /// @brief internal and reserved protocols by kernel. + constexpr const Char* kURLProtocols[] = { + "file", // Filesystem protocol + "zup", // ZKA update protocol + "oscc", // Open System Configuration Connectivity. + "odbc", // ODBC connectivity. + "https", // HTTPS layer driver (HTTPS.sys). + }; + + constexpr const int kUrlOutSz = 1; //! such as: :// + constexpr const int kProtosCount = 5; + 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 Kernel diff --git a/dev/ZKA/Sources/User.cxx b/dev/ZKA/Sources/User.cxx new file mode 100644 index 00000000..e05aa283 --- /dev/null +++ b/dev/ZKA/Sources/User.cxx @@ -0,0 +1,240 @@ +/* + * ======================================================== + * + * ZKA + * Copyright ZKA Technologies., all rights reserved. + * + * File: User.cxx + * Purpose: User concept and management. + * + * ======================================================== + */ + +#include <KernelKit/User.hxx> +#include <NewKit/KernelCheck.hxx> +#include <KernelKit/FileManager.hxx> +#include <KernelKit/ProcessScheduler.hxx> + +#include <KernelKit/Heap.hxx> + +#define cStdUser (0xCF) +#define cSuperUser (0xEF) + +/// BUGS: 0 + +namespace Kernel +{ + namespace Detail + { + /// \brief Constructs a token by hashing the password. + /// \param password password to hash. + /// \return the hashed password + const Int32 cred_construct_token(Char* password, User* user) + { + if (!password || !user) + return -1; + + for (Size i_pass = 0; i_pass < rt_string_len(password); ++i_pass) + { + Char cur_chr = password[i_pass]; + password[i_pass] = cur_chr + (user->IsStdUser() ? cStdUser : cSuperUser); + } + + return 0; + } + } // namespace Detail + + User::User(const Int32& sel, const Char* userName) + : fRing((RingKind)sel) + { + MUST_PASS(sel >= 0); + this->fUserName += userName; + } + + User::User(const RingKind& ringKind, const Char* userName) + : fRing(ringKind) + { + this->fUserName += userName; + } + + User::~User() = default; + + Bool User::TrySave(const Char* password) noexcept + { + kcout << "Trying to save password...\r"; + + SizeT len = rt_string_len(password); + + Char* token = new Char[len]; + + MUST_PASS(token); + + rt_copy_memory((VoidPtr)password, token, rt_string_len(password)); + + Detail::cred_construct_token(token, this); + + if (NewFilesystemManager::GetMounted()) + { + auto node = NewFilesystemManager::GetMounted()->Create(kUsersFile); + + if (node) + { + NewFilesystemManager::GetMounted()->Write(this->fUserName.CData(), node, (VoidPtr)token, (this->IsStdUser() ? cStdUser : cSuperUser) | kNewFSCatalogKindMetaFile, len); + delete node; + } + + delete token; + return true; + } + + delete token; + return false; + } + + bool User::operator==(const User& lhs) + { + return lhs.fRing == this->fRing; + } + + bool User::operator!=(const User& lhs) + { + return lhs.fRing != this->fRing; + } + + StringView& User::Name() noexcept + { + return this->fUserName; + } + + const RingKind& User::Ring() noexcept + { + return this->fRing; + } + + Bool User::IsStdUser() noexcept + { + return this->Ring() == RingKind::kRingStdUser; + } + + Bool User::IsSuperUser() noexcept + { + return this->Ring() == RingKind::kRingSuperUser; + } + + UserManager* UserManager::The() noexcept + { + UserManager* view = nullptr; + + if (!view) + view = new UserManager(); + + return view; + } + + Bool UserManager::TryLogIn(User* user, const Char* password) noexcept + { + if (!password || + !user) + { + ErrLocal() = kErrorInvalidData; + + kcout << "newoskrnl: Incorrect data given.\r"; + + return false; + } + + kcout << "newoskrnl: Trying to log-in.\r"; + + FileStreamUTF8 file(kUsersFile, "rb"); + + // ------------------------------------------ // + // Retrieve token from a specific file fork. + // ------------------------------------------ // + + auto token = file.Read(user->fUserName.CData()); + + if (!token) + { + ErrLocal() = kErrorInvalidCreds; + + kcout << "newoskrnl: Incorrect credentials.\r"; + return false; + } + else + { + Char generated_token[255] = {0}; + + // ================================================== // + // Provide password on token variable. + // ================================================== // + + rt_copy_memory((VoidPtr)password, generated_token, rt_string_len(password)); + + // ================================================== // + // Construct token. + // ================================================== // + + Detail::cred_construct_token(generated_token, user); + + // ================================================== // + // Checks if it matches the current token we have. + // ================================================== // + + if (rt_string_cmp((Char*)token, generated_token, rt_string_len(password))) + { + kcout << "newoskrnl: Incorrect credentials.\r"; + + mm_delete_ke_heap(token); + return false; + } + + kcout << "newoskrnl: Credentials are correct, moving on.\r"; + } + + // ------------------------------------------ // + // This was successful, continue. + // ------------------------------------------ // + + user->fUserToken = token; + + if (fCurrentUser) + { + if (!fLastLoggedOffUser) + { + fLastLoggedOffUser = fCurrentUser; + } + else + { + this->TryLogOff(); + } + } + + fCurrentUser = user; + Kernel::kcout << "newoskrnl: Logged in as: " << fCurrentUser->Name().CData() << Kernel::endl; + + return true; + } + + User* UserManager::GetCurrent() noexcept + { + return fCurrentUser; + } + + Void UserManager::TryLogOff() noexcept + { + if (!fCurrentUser) + return; + + // an illegal operation just occured, we can't risk more. + if (fCurrentUser == fRootUser) + { + ke_stop(RUNTIME_CHECK_BOOTSTRAP); + } + + if (fLastLoggedOffUser) + delete fLastLoggedOffUser; + + fLastLoggedOffUser = nullptr; + fLastLoggedOffUser = fCurrentUser; + } +} // namespace Kernel diff --git a/dev/ZKA/Sources/Utils.cxx b/dev/ZKA/Sources/Utils.cxx new file mode 100644 index 00000000..5673c5fd --- /dev/null +++ b/dev/ZKA/Sources/Utils.cxx @@ -0,0 +1,257 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Utils.hxx> +#include <KernelKit/DebugOutput.hxx> + +namespace Kernel +{ + Int rt_string_cmp(const Char* src, const Char* cmp, Size size) + { + if (!cmp || + !src) + return 1; + + 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) + { + Size len{0}; + while (str[len] != '\0') + { + if (len > _len) + { + return 0; + } + + len++; + } + + return len; + } + + Size rt_string_len(const Char* ptr) + { + if (*ptr == 0) + return 0; + + SizeT cnt = 0; + + while (ptr[cnt] != (Char)0) + { + 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 (SizeT i = 0; i < rt_string_len(in); ++i) + { + if (rt_string_cmp(in + i, needle, rt_string_len(needle)) == 0) + return reinterpret_cast<voidPtr>(const_cast<char*>(in + i)); + } + + return nullptr; + } + + // @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 Kernel + +#ifdef __FREESTANDING__ + +//////////////////////////////////////////////////////////////////////////////////////// +/// Exported C functions +//////////////////////////////////////////////////////////////////////////////////////// + +/// @brief memset in C++ +EXTERN_C void memset(void* dst, char src, Kernel::SizeT len) +{ + Kernel::rt_set_memory(dst, src, len); +} + +/// @brief memcpy in C++ +EXTERN_C void memcpy(void* dst, void* src, Kernel::SizeT len) +{ + Kernel::rt_copy_memory(src, dst, len); +} + +/// @brief memmove in C++ +EXTERN_C void* memmove(void* dst, void* src, Kernel::SizeT len) +{ + Kernel::rt_copy_memory(src, dst, len); + return dst; +} + +/// @brief strlen definition in C++. +EXTERN_C Kernel::SizeT strlen(const char* whatToCheck) +{ + return Kernel::rt_string_len(whatToCheck); +} + +/// @brief memcmp in C++ +EXTERN_C Kernel::SizeT memcmp(void* dst, void* src, Kernel::SizeT len) +{ + return Kernel::rt_string_cmp((char*)src, (char*)dst, len); +} + +/// @brief strcmp in C++ +EXTERN_C Kernel::SizeT strcmp(char* dst, char* src, Kernel::SizeT len) +{ + return Kernel::rt_string_cmp(src, dst, len); +} + +#endif // __FREESTANDING__
\ No newline at end of file diff --git a/dev/ZKA/Sources/Variant.cxx b/dev/ZKA/Sources/Variant.cxx new file mode 100644 index 00000000..97775900 --- /dev/null +++ b/dev/ZKA/Sources/Variant.cxx @@ -0,0 +1,28 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <NewKit/Variant.hxx> + +namespace Kernel +{ + const Char* Variant::ToString() + { + switch (fKind) + { + case VariantKind::kJson: + return ("Class:{Json}"); + case VariantKind::kString: + return ("Class:{String}"); + case VariantKind::kBlob: + return ("Class:{Blob}"); + default: + return ("Class:{Null}"); + } + } + + /// @brief Leak variant's instance. + VoidPtr Variant::Leak() { return fPtr; } +} // namespace Kernel diff --git a/dev/ZKA/Sources/compile_flags.txt b/dev/ZKA/Sources/compile_flags.txt new file mode 100644 index 00000000..b02c5e3d --- /dev/null +++ b/dev/ZKA/Sources/compile_flags.txt @@ -0,0 +1,7 @@ +-nostdlib +-ffreestanding +-std=c++20 +-I../ +-I$(HOME)/ +-D__FSKIT_USE_NEWFS__ +-D__NEWOS_AMD64__ |
