diff options
| author | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2025-03-23 19:13:48 +0100 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2025-03-23 19:15:17 +0100 |
| commit | a13e1c0911c0627184bc38f18c7fdda64447b3ad (patch) | |
| tree | 073a62c09bf216e85a3f310376640fa1805147f9 /dev/kernel | |
| parent | 149fa096eb306d03686b3b67e813cf1a78e08cd0 (diff) | |
meta(kernel): Reworked repository's filesystem structure.
Removing useless parts of the project too.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'dev/kernel')
252 files changed, 19798 insertions, 0 deletions
diff --git a/dev/kernel/ArchKit/ArchKit.h b/dev/kernel/ArchKit/ArchKit.h new file mode 100644 index 00000000..04fc5bf6 --- /dev/null +++ b/dev/kernel/ArchKit/ArchKit.h @@ -0,0 +1,94 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/Function.h> + +#include <FirmwareKit/Handover.h> + +#ifdef __NE_AMD64__ +#include <HALKit/AMD64/Paging.h> +#include <HALKit/AMD64/Hypervisor.h> +#include <HALKit/AMD64/Processor.h> +#elif defined(__NE_POWER64__) +#include <HALKit/POWER/Processor.h> +#elif defined(__NE_ARM64__) +#include <HALKit/ARM64/Processor.h> +#elif defined(__NE_SDK__) +#include <HALKit/ARM64/Processor.h> +#else +#error !!! unknown architecture !!! +#endif + +#define kKernelMaxSystemCalls (512U) + +namespace NeOS +{ + inline SSizeT rt_hash_seed(const Char* seed, int mul) + { + SSizeT hash = 0; + + for (SSizeT idx = 0; seed[idx] != 0; ++idx) + { + hash += seed[idx]; + hash ^= mul; + } + + return hash; + } + + /// @brief write to mapped memory register + /// @param base the base address. + /// @param reg the register. + /// @param value the write to write on it. + template <typename DataKind> + inline Void ke_dma_write(UIntPtr base, DataKind reg, DataKind value) noexcept + { + *(volatile DataKind*)(base + reg) = value; + } + + /// @brief read from mapped memory register. + /// @param base base address + /// @param reg the register. + /// @return the value inside the register. + template <typename DataKind> + inline UInt32 ke_dma_read(UIntPtr base, DataKind reg) noexcept + { + return *(volatile DataKind*)(base + reg); + } + + namespace HAL + { + auto mm_is_bitmap(VoidPtr ptr) -> Bool; + } +} // namespace NeOS + +typedef NeOS::Void (*rt_syscall_proc)(NeOS::VoidPtr); + +struct HalSyscallEntry final +{ + NeOS::Int64 fHash; + NeOS::Bool fHooked; + rt_syscall_proc fProc; + + operator bool() + { + return fHooked; + } +}; + +inline NeOS::Array<HalSyscallEntry, + kKernelMaxSystemCalls> + kSyscalls; + +inline NeOS::Array<HalSyscallEntry, + kKernelMaxSystemCalls> + kKerncalls; + +EXTERN_C NeOS::HAL::StackFramePtr mp_get_current_context(NeOS::Int64 pid); diff --git a/dev/kernel/CFKit/GUIDWizard.h b/dev/kernel/CFKit/GUIDWizard.h new file mode 100644 index 00000000..5236688f --- /dev/null +++ b/dev/kernel/CFKit/GUIDWizard.h @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <CFKit/GUIDWrapper.h> +#include <NewKit/Array.h> +#include <NewKit/ArrayList.h> +#include <NewKit/Defines.h> +#include <NewKit/ErrorOr.h> +#include <NewKit/Ref.h> +#include <NewKit/Stream.h> +#include <NewKit/KString.h> + +namespace CFKit::XRN::Version1 +{ + using namespace NeOS; + + Ref<GUIDSequence*> cf_make_sequence(const ArrayList<UInt32>& seq); + ErrorOr<Ref<NeOS::KString>> cf_try_guid_to_string(Ref<GUIDSequence*>& guid); +} // namespace CFKit::XRN::Version1 diff --git a/dev/kernel/CFKit/GUIDWrapper.h b/dev/kernel/CFKit/GUIDWrapper.h new file mode 100644 index 00000000..3b7ada6d --- /dev/null +++ b/dev/kernel/CFKit/GUIDWrapper.h @@ -0,0 +1,60 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/Ref.h> +#include <NewKit/Stream.h> + +/* GUID for C++ Components */ + +#define kXRNNil "@{........-....-M...-N...-............}" + +// eXtensible Resource Information +namespace CFKit::XRN +{ + using namespace NeOS; + + union GUIDSequence { + alignas(8) UShort u8[16]; + alignas(8) UShort u16[8]; + alignas(8) UInt u32[4]; + alignas(8) ULong u64[2]; + + struct + { + alignas(8) UInt fMs1; + UShort fMs2; + UShort fMs3; + UChar fMs4[8]; + }; + }; + + class GUID final + { + public: + explicit GUID() = default; + ~GUID() = default; + + public: + GUID& operator=(const GUID&) = default; + GUID(const GUID&) = default; + + public: + GUIDSequence& operator->() noexcept + { + return fUUID; + } + GUIDSequence& Leak() noexcept + { + return fUUID; + } + + private: + GUIDSequence fUUID; + }; +} // namespace CFKit::XRN diff --git a/dev/kernel/CFKit/Property.h b/dev/kernel/CFKit/Property.h new file mode 100644 index 00000000..e4588ad6 --- /dev/null +++ b/dev/kernel/CFKit/Property.h @@ -0,0 +1,56 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef CFKIT_PROPS_H +#define CFKIT_PROPS_H + +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/Function.h> +#include <NewKit/KString.h> +#include <CFKit/GUIDWrapper.h> + +#define kMaxPropLen (256U) + +namespace CFKit +{ + using namespace NeOS; + + /// @brief handle to anything (number, ptr, string...) + using PropertyId = UIntPtr; + + /// @brief Kernel property class. + /// @example /prop/smp_max or /prop/kern_ver + class Property + { + public: + Property(); + virtual ~Property(); + + public: + Property& operator=(const Property&) = default; + Property(const Property&) = default; + + BOOL StringEquals(KString& name); + PropertyId& GetValue(); + KString& GetKey(); + + private: + KString fName{kMaxPropLen}; + PropertyId fValue{0UL}; + Ref<XRN::GUID> fGUID{}; + }; + + template <SizeT N> + using PropertyArray = Array<Property, N>; +} // namespace CFKit + +namespace NeOS +{ + using namespace CFKit; +} + +#endif // !CFKIT_PROPS_H diff --git a/dev/kernel/CFKit/Utils.h b/dev/kernel/CFKit/Utils.h new file mode 100644 index 00000000..b8f16164 --- /dev/null +++ b/dev/kernel/CFKit/Utils.h @@ -0,0 +1,55 @@ +#ifndef CFKIT_UTILS_H +#define CFKIT_UTILS_H + +#include <KernelKit/PE.h> +#include <KernelKit/MSDOS.h> + +namespace CFKit +{ + using namespace NeOS; + + /// @brief Finds the PE header inside the blob. + inline auto ldr_find_exec_header(DosHeaderPtr ptrDos) -> LDR_EXEC_HEADER_PTR + { + if (!ptrDos) + return nullptr; + + if (ptrDos->eMagic[0] != kMagMz0) + return nullptr; + + if (ptrDos->eMagic[1] != kMagMz1) + return nullptr; + + return (LDR_EXEC_HEADER_PTR)(VoidPtr)(&ptrDos->eLfanew + 1); + } + + /// @brief Finds the PE optional header inside the blob. + inline auto ldr_find_opt_exec_header(DosHeaderPtr ptrDos) -> LDR_OPTIONAL_HEADER_PTR + { + if (!ptrDos) + return nullptr; + + auto exec = ldr_find_exec_header(ptrDos); + + if (!exec) + return nullptr; + + return (LDR_OPTIONAL_HEADER_PTR)(VoidPtr)(&exec->Characteristics + 1); + } + + /// @brief Finds the PE header inside the blob. + /// @note overloaded function. + inline auto ldr_find_exec_header(const Char* ptrDos) -> LDR_EXEC_HEADER_PTR + { + return ldr_find_exec_header((DosHeaderPtr)ptrDos); + } + + /// @brief Finds the PE header inside the blob. + /// @note overloaded function. + inline auto ldr_find_opt_exec_header(const Char* ptrDos) -> LDR_OPTIONAL_HEADER_PTR + { + return ldr_find_opt_exec_header((DosHeaderPtr)ptrDos); + } +} // namespace CFKit + +#endif // ifndef CFKIT_UTILS_H diff --git a/dev/kernel/CompilerKit/CompilerKit.h b/dev/kernel/CompilerKit/CompilerKit.h new file mode 100644 index 00000000..c1a5f424 --- /dev/null +++ b/dev/kernel/CompilerKit/CompilerKit.h @@ -0,0 +1,13 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef _INC_CL_H +#define _INC_CL_H + +#include <CompilerKit/Detail.h> +#include <CompilerKit/Version.h> + +#endif /* ifndef _INC_CL_H */ diff --git a/dev/kernel/CompilerKit/Detail.h b/dev/kernel/CompilerKit/Detail.h new file mode 100644 index 00000000..c098f273 --- /dev/null +++ b/dev/kernel/CompilerKit/Detail.h @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#ifdef __NEOSKRNL__ +#include <NewKit/Defines.h> +#endif // ifdef __NEOSKRNL__ + +#define NE_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define NE_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define NE_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define NE_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; diff --git a/dev/kernel/CompilerKit/Version.h b/dev/kernel/CompilerKit/Version.h new file mode 100644 index 00000000..11854cd8 --- /dev/null +++ b/dev/kernel/CompilerKit/Version.h @@ -0,0 +1,7 @@ +// (c) Amlal EL Mahrouss + +#pragma once + +/// <COMMIT NUMBER>.<YEAR>.<PROGRAM VERSION> +#define BOOTLOADER_VERSION "1104.2025.110" +#define KERNEL_VERSION "1104.2025.110" diff --git a/dev/kernel/FSKit/Defines.h b/dev/kernel/FSKit/Defines.h new file mode 100644 index 00000000..9431a9c0 --- /dev/null +++ b/dev/kernel/FSKit/Defines.h @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +#define FSKIT_VERSION "1.0.0" +#define FSKIT_VERSION_BCD 0x0100 diff --git a/dev/kernel/FSKit/HeFS.h b/dev/kernel/FSKit/HeFS.h new file mode 100644 index 00000000..6911ddef --- /dev/null +++ b/dev/kernel/FSKit/HeFS.h @@ -0,0 +1,59 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#pragma once
+
+#include <NewKit/Defines.h>
+
+/// @file HeFS.h
+/// @brief HeFS filesystem support.
+
+#define kHeFSVersion (0x0100)
+#define kHeFSMagic " HeFS"
+#define kHeFSMagicLen (8)
+
+#define kHeFSFileNameLen (256U)
+#define kHeFSPartNameLen (256U)
+
+#define kHeFSMinimumDiskSize (gib_cast(64))
+
+enum
+{
+ kHeFSInvalidDrive,
+ kHeFSHDDDrive,
+ kHeFSSSDDrive,
+ kHeFSMassStorageDrive,
+ kHeFSSCSIDrive,
+ kHeFSDriveCount,
+};
+
+struct HeFS_BOOT_NODE;
+
+struct HeFS_BOOT_NODE final
+{
+ NeOS::Char fMagic[kHeFSMagicLen];
+ NeOS::Char fPartName[kHeFSPartNameLen];
+ NeOS::UInt32 fVersion;
+ NeOS::UInt64 fBadSectors;
+ NeOS::UInt64 fSectorCount;
+ NeOS::UInt64 fSectorSize;
+ NeOS::UInt32 fChecksum;
+ NeOS::UInt8 fDriveKind;
+ NeOS::UInt8 fTextEncoding;
+ NeOS::UInt64 fRootINode;
+ NeOS::UInt64 fRecoveryINode;
+};
+
+struct HeFS_INDEX_NODE
+{
+ NeOS::Char fName[kHeFSFileNameLen];
+ NeOS::UInt32 fFlags;
+ NeOS::UInt16 fKind;
+ NeOS::UInt32 fSize;
+ NeOS::Lba fFirstINode;
+ NeOS::Lba fLastINode;
+ NeOS::UInt32 fChecksum;
+};
\ No newline at end of file diff --git a/dev/kernel/FSKit/IndexableProperty.h b/dev/kernel/FSKit/IndexableProperty.h new file mode 100644 index 00000000..6a79bc1b --- /dev/null +++ b/dev/kernel/FSKit/IndexableProperty.h @@ -0,0 +1,63 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <CFKit/Property.h> +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/DriveMgr.h> + +#define kIndexerCatalogNameLength 256U +#define kIndexerClaimed 0xCF + +namespace NeOS +{ + namespace Indexer + { + struct IndexProperty final + { + public: + Char Drive[kDriveNameLen]; + Char Path[kIndexerCatalogNameLength]; + }; + + class IndexableProperty final : public Property + { + public: + explicit IndexableProperty() + : Property() + { + NeOS::KString strProp(kMaxPropLen); + strProp += "/prop/indexable"; + + this->GetKey() = strProp; + } + + ~IndexableProperty() override = default; + + NE_COPY_DEFAULT(IndexableProperty); + + public: + IndexProperty& Leak() noexcept; + + public: + void AddFlag(Int16 flag); + void RemoveFlag(Int16 flag); + Int16 HasFlag(Int16 flag); + + private: + IndexProperty fIndex; + UInt32 fFlags; + }; + + /// @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); + } // namespace Indexer +} // namespace NeOS diff --git a/dev/kernel/FSKit/NeFS.h b/dev/kernel/FSKit/NeFS.h new file mode 100644 index 00000000..b2f7095d --- /dev/null +++ b/dev/kernel/FSKit/NeFS.h @@ -0,0 +1,445 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + FILE: NeFS.h + PURPOSE: NeFS (New extended File System) support. + + Revision History: + + ?/?/?: Added file (amlel) + 12/02/24: Add UUID macro for EPM and GPT partition schemes. + 3/16/24: Add mandatory sector size, kNeFSSectorSz is set to 2048 by +default. + +------------------------------------------- */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <HintsKit/CompilerHint.h> +#include <KernelKit/DriveMgr.h> +#include <NewKit/Defines.h> +#include <NewKit/KString.h> + +/** + @brief New extended File System specification. + @author Amlal EL Mahrouss (Amlal EL Mahrouss, amlalelmahrouss at icloud dot com) +*/ + +#define kNeFSInvalidFork (-1) +#define kNeFSInvalidCatalog (-1) +#define kNeFSCatalogNameLen (256) + +#define kNeFSMinimumDiskSize (gib_cast(4)) + +#define kNeFSSectorSz (512) + +#define kNeFSIdentLen (8) +#define kNeFSIdent " NeFS" +#define kNeFSPadLen (392) + +#define kNeFSMetaFilePrefix '$' + +#define kNeFSVersionInteger (0x0129) +#define kNeFSVerionString "1.2.9" + +/// @brief Standard fork types. +#define kNeFSDataFork "main_data" +#define kNeFSResourceFork "main_rsrc" + +#define kNeFSForkSize (sizeof(NEFS_FORK_STRUCT)) + +#define kNeFSPartitionTypeStandard (7) +#define kNeFSPartitionTypePage (8) +#define kNeFSPartitionTypeBoot (9) + +#define kNeFSCatalogKindFile (1) +#define kNeFSCatalogKindDir (2) +#define kNeFSCatalogKindAlias (3) + +//! Shared between network and/or partitions. Export forks as .zip when copying. +#define kNeFSCatalogKindShared (4) + +#define kNeFSCatalogKindResource (5) +#define kNeFSCatalogKindExecutable (6) + +#define kNeFSCatalogKindPage (8) + +#define kNeFSCatalogKindDevice (9) +#define kNeFSCatalogKindLock (10) + +#define kNeFSCatalogKindRLE (11) +#define kNeFSCatalogKindMetaFile (12) + +#define kNeFSCatalogKindTTF (13) +#define kNeFSCatalogKindRIFF (14) +#define kNeFSCatalogKindMPEG (15) +#define kNeFSCatalogKindMOFF (16) + +#define kNeFSSeparator '/' +#define kNeFSSeparatorAlt '/' + +#define kNeFSUpDir ".." +#define kNeFSRoot "/" +#define kNeFSRootAlt "/" + +#define kNeFSLF '\r' +#define kNeFSEOF (-1) + +#define kNeFSBitWidth (sizeof(NeOS::Char)) +#define kNeFSLbaType (NeOS::Lba) + +/// @note Start after the partition map header. (Virtual addressing) +#define kNeFSRootCatalogStartAddress (1024) +#define kNeFSCatalogStartAddress (kNeFSRootCatalogStartAddress + sizeof(NEFS_ROOT_PARTITION_BLOCK)) + +#define kResourceTypeDialog (10) +#define kResourceTypeString (11) +#define kResourceTypeMenu (12) +#define kResourceTypeSound (13) +#define kResourceTypeFont (14) +#define kNeFSPartLen (32) + +#define kNeFSFlagDeleted (70) +#define kNeFSFlagUnallocated (0) +#define kNeFSFlagCreated (71) + +#define kNeFSMimeNameLen (200) +#define kNeFSForkNameLen (200) + +#define kNeFSFrameworkExt ".fwrk/" +#define kNeFSStepsExt ".step/" +#define kNeFSApplicationExt ".app/" +#define kNeFSJournalExt ".jrnl" + +struct NEFS_CATALOG_STRUCT; +struct NEFS_FORK_STRUCT; +struct NEFS_ROOT_PARTITION_BLOCK; + +enum +{ + kNeFSHardDrive = 0xC0, // Hard Drive + kNeFSSolidStateDrive = 0xC1, // Solid State Drive + kNeFSOpticalDrive = 0x0C, // Blu-Ray/DVD + kNeFSMassStorageDevice = 0xCC, // USB + kNeFSScsiDrive = 0xC4, // SCSI Hard Drive + kNeFSFlashDrive = 0xC6, + kNeFSUnknown = 0xFF, // Unknown device. + kNeFSDriveCount = 7, +}; + +enum +{ + kNeFSStatusUnlocked = 0x18, + kNeFSStatusLocked, + kNeFSStatusError, + kNeFSStatusInvalid, +}; + +/// @brief Catalog type. +struct PACKED NEFS_CATALOG_STRUCT final +{ + BOOL ForkOrCatalog : 1 {0}; + + NeOS::Char Name[kNeFSCatalogNameLen] = {0}; + NeOS::Char Mime[kNeFSMimeNameLen] = {0}; + + /// Catalog flags. + NeOS::UInt16 Flags; + + /// Catalog allocation status. + NeOS::UInt16 Status; + + /// Custom catalog flags. + NeOS::UInt16 CatalogFlags; + + /// Catalog kind. + NeOS::Int32 Kind; + + /// Size of the data fork. + NeOS::Lba DataForkSize; + + /// Size of all resource forks. + NeOS::Lba ResourceForkSize; + + /// Forks LBA. + NeOS::Lba DataFork; + NeOS::Lba ResourceFork; + + /// Buddy allocation tracker. + NeOS::Lba NextSibling; + NeOS::Lba PrevSibling; + + /// Best-buddy tracker. + NeOS::Lba NextBestSibling; + NeOS::Lba NextPrevSibling; + + NeOS::UInt32 Checksum; +}; + +/// @brief Fork type, contains a data page. +/// @note The way we store is way different than how other filesystems do, specific chunk of code are +/// written into either the data fork or resource fork, the resource fork is reserved for file metadata. +/// whereas the data fork is reserved for file data. +struct PACKED NEFS_FORK_STRUCT final +{ + BOOL ForkOrCatalog : 1 {1}; + + NeOS::Char ForkName[kNeFSForkNameLen] = {0}; + NeOS::Char CatalogName[kNeFSCatalogNameLen] = {0}; + + NeOS::Int32 Flags; + NeOS::Int32 Kind; + + NeOS::Int64 ResourceId; + NeOS::Int32 ResourceKind; + NeOS::Int32 ResourceFlags; + + NeOS::Lba DataOffset; // 8 Where to look for this data? + NeOS::SizeT DataSize; /// Data size according using sector count. + + NeOS::Lba NextSibling; + NeOS::Lba PreviousSibling; + + NeOS::Char Pad[2] = {0}; +}; + +/// @brief Partition block type +struct PACKED NEFS_ROOT_PARTITION_BLOCK final +{ + NeOS::Char Ident[kNeFSIdentLen] = {0}; + NeOS::Char PartitionName[kNeFSPartLen] = {0}; + + NeOS::Int32 Flags; + NeOS::Int32 Kind; + + NeOS::Lba StartCatalog; + NeOS::SizeT CatalogCount; + + NeOS::SizeT DiskSize; + + NeOS::SizeT FreeCatalog; + NeOS::SizeT FreeSectors; + + NeOS::SizeT SectorCount; + NeOS::SizeT SectorSize; + + NeOS::UInt64 Version; + + NeOS::Lba EpmBlock; + + NeOS::Char Pad[kNeFSPadLen]; +}; + +namespace NeOS +{ + class NeFileSystemParser; + class NeFileSystemJournal; + class NeFileSystemHelper; + + enum + { + kNeFSSubDriveA, + kNeFSSubDriveB, + kNeFSSubDriveC, + kNeFSSubDriveD, + kNeFSSubDriveInvalid, + kNeFSSubDriveCount, + }; + + /// \brief Resource fork kind. + enum + { + kNeFSRsrcForkKind = 0, + kNeFSDataForkKind = 1 + }; + + /// + /// \name NeFileSystemParser + /// \brief NeFS parser class. (catalog creation, remove removal, root, + /// forks...) Designed like the DOM, detects the filesystem automatically. + /// + class NeFileSystemParser final + { + public: + explicit NeFileSystemParser() = default; + ~NeFileSystemParser() = default; + + public: + NE_COPY_DEFAULT(NeFileSystemParser); + + public: + /// @brief Creates a new fork inside the NeFS partition. + /// @param catalog it's catalog + /// @param theFork the fork itself. + /// @return the fork + _Output BOOL CreateFork(_Input NEFS_FORK_STRUCT& in); + + /// @brief Find fork inside New filesystem. + /// @param catalog the catalog. + /// @param name the fork name. + /// @return the fork. + _Output NEFS_FORK_STRUCT* FindFork(_Input NEFS_CATALOG_STRUCT* catalog, + _Input const Char* name, + Boolean data); + + _Output Void RemoveFork(_Input NEFS_FORK_STRUCT* fork); + + _Output Void CloseFork(_Input NEFS_FORK_STRUCT* fork); + + _Output NEFS_CATALOG_STRUCT* FindCatalog(_Input const Char* catalog_name, Lba& ou_lba, Bool search_hidden = YES, Bool local_search = NO); + + _Output NEFS_CATALOG_STRUCT* GetCatalog(_Input const Char* name); + + _Output NEFS_CATALOG_STRUCT* CreateCatalog(_Input const Char* name, + _Input const Int32& flags, + _Input const Int32& kind); + + _Output NEFS_CATALOG_STRUCT* CreateCatalog(_Input const Char* name); + + _Output Bool WriteCatalog(_Input const Char* catalog, + _Input Bool rsrc, + _Input VoidPtr data, + _Input SizeT sz, + _Input const Char* name); + + _Output VoidPtr ReadCatalog(_Input _Output NEFS_CATALOG_STRUCT* catalog, + _Input Bool isRsrcFork, + _Input SizeT dataSz, + _Input const Char* forkName); + + _Output Bool Seek(_Input _Output NEFS_CATALOG_STRUCT* catalog, SizeT off); + + _Output SizeT Tell(_Input _Output NEFS_CATALOG_STRUCT* catalog); + + _Output Bool RemoveCatalog(_Input const Char* catalog); + + _Output Bool CloseCatalog(_InOut NEFS_CATALOG_STRUCT* catalog); + + /// @brief Make a EPM+NeFS drive out of the disk. + /// @param drive The drive to write on. + /// @return If it was sucessful, see err_local_get(). + _Output Bool Format(_Input _Output DriveTrait* drive, _Input const Lba endLba, _Input const Int32 flags, const Char* part_name); + + public: + UInt32 mDriveIndex{kNeFSSubDriveA}; + }; + + /// + /// \name NeFileSystemHelper + /// \brief Filesystem helper and utils. + /// + + class NeFileSystemHelper final + { + public: + STATIC const Char* Root(); + STATIC const Char* UpDir(); + STATIC const Char Separator(); + STATIC const Char MetaFile(); + }; + + /// @brief Journal class for NeFS. + class NeFileSystemJournal final + { + private: + NEFS_CATALOG_STRUCT* mNode{nullptr}; + + public: + explicit NeFileSystemJournal(const char* stamp = nullptr) + { + if (!stamp) + { + kout << "Invalid: Journal Stamp, using default name.\r"; + return; + } + + kout << "Info: Journal stamp: " << stamp << kendl; + rt_copy_memory((VoidPtr)stamp, this->mStamp, rt_string_len(stamp)); + } + + ~NeFileSystemJournal() = default; + + NE_COPY_DEFAULT(NeFileSystemJournal); + + Bool CreateJournal(NeFileSystemParser* parser) + { + if (!parser) + return NO; + + delete parser->CreateCatalog("/etc/xml/", 0, kNeFSCatalogKindDir); + mNode = parser->CreateCatalog(mStamp); + + if (!mNode) + return NO; + + return YES; + } + + Bool GetJournal(NeFileSystemParser* parser) + { + if (!parser) + return NO; + + auto node = parser->GetCatalog(mStamp); + + if (node) + { + mNode = node; + return YES; + } + + return NO; + } + + Bool ReleaseJournal() + { + if (mNode) + { + delete mNode; + mNode = nullptr; + return YES; + } + + return NO; + } + + Bool CommitJournal(NeFileSystemParser* parser, + Char* xml_data, + Char* journal_name) + { + if (!parser || + !mNode) + return NO; + + NEFS_FORK_STRUCT new_fork{}; + + rt_copy_memory(mStamp, new_fork.CatalogName, rt_string_len(mStamp)); + rt_copy_memory(journal_name, new_fork.ForkName, rt_string_len(journal_name)); + + new_fork.ResourceKind = 0; + new_fork.ResourceId = 0; + new_fork.ResourceFlags = 0; + new_fork.DataSize = rt_string_len(xml_data); + new_fork.Kind = kNeFSRsrcForkKind; + + if (!parser->CreateFork(new_fork)) + return NO; + + kout << "XML Commited: " << xml_data << "\r\nTo Journal Fork: " << journal_name << kendl; + + auto ret = parser->WriteCatalog(new_fork.CatalogName, YES, xml_data, rt_string_len(xml_data), new_fork.ForkName); + + return ret; + } + + private: + Char mStamp[kNeFSCatalogNameLen] = {"/etc/xml/journal" kNeFSJournalExt}; + }; + + namespace NeFS + { + Boolean fs_init_nefs(Void) noexcept; + } // namespace NeFS +} // namespace NeOS diff --git a/dev/kernel/FirmwareKit/.gitkeep b/dev/kernel/FirmwareKit/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/dev/kernel/FirmwareKit/.gitkeep @@ -0,0 +1 @@ + diff --git a/dev/kernel/FirmwareKit/CoreBoot/CoreBoot.h b/dev/kernel/FirmwareKit/CoreBoot/CoreBoot.h new file mode 100644 index 00000000..5fe3f4ea --- /dev/null +++ b/dev/kernel/FirmwareKit/CoreBoot/CoreBoot.h @@ -0,0 +1,31 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace Firmware::Detail::CoreBoot +{ + using namespace NeOS; + + struct LEHeader; + + /// @brief Linear Executable Header + /// @author Amlal EL Mahrouss + struct ATTRIBUTE(aligned(4)) LEHeader + { + const Char fMagic[2]; // magic number + const Char fName[10]; // operating system name + const UInt32 fRevision; // firmware revision + const UInt32 fStartAddress; // start address (master/slave(s) thread) + +#ifdef NE_IS_EXTENDED_COREBOOT + const UIntPtr fMasterStructure; // master structure for MP/PM and device tree and such (ARM) + const UIntPtr fMasterStructureVersion; // master structure version. +#endif + }; +} // namespace Firmware::Detail::CoreBoot diff --git a/dev/kernel/FirmwareKit/CoreBoot/NS.h b/dev/kernel/FirmwareKit/CoreBoot/NS.h new file mode 100644 index 00000000..95576de8 --- /dev/null +++ b/dev/kernel/FirmwareKit/CoreBoot/NS.h @@ -0,0 +1,10 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <FirmwareKit/CoreBoot/CoreBoot.h> +#include <FirmwareKit/CoreBoot/NetBoot.h>
\ No newline at end of file diff --git a/dev/kernel/FirmwareKit/CoreBoot/NetBoot.h b/dev/kernel/FirmwareKit/CoreBoot/NetBoot.h new file mode 100644 index 00000000..21ce02ba --- /dev/null +++ b/dev/kernel/FirmwareKit/CoreBoot/NetBoot.h @@ -0,0 +1,25 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +/// @brief the internet header is used to download updates OTA. +typedef struct NETBOOT_INTERNET_HEADER +{ + NeOS::Char NB1; /// magic char 1 'N' + NeOS::Char NB2; /// magic char 2 'E' + NeOS::Char NB3; /// magic char 3 'T' + NeOS::Char NB4; /// magic char 4 'B' + + NeOS::Char PatchName[256U]; /// example: ColdChoco + NeOS::Int32 PatchLength; /// the patch length. + NeOS::Char PatchTarget[256U]; /// the target file. + NeOS::Boolean ImpliesROM; /// does it imply an EEPROM reprogram? + NeOS::Boolean Preflight; /// is it a preflight packet. + NeOS::Char Patch[]; /// non preflight packet has a patch blob for a **PatchTarget** +} NETBOOT_INTERNET_HEADER; diff --git a/dev/kernel/FirmwareKit/EFI.h b/dev/kernel/FirmwareKit/EFI.h new file mode 100644 index 00000000..57f7e17a --- /dev/null +++ b/dev/kernel/FirmwareKit/EFI.h @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <FirmwareKit/EFI/EFI.h> + +/// @note this header is used to reference the EFI/EFI.h diff --git a/dev/kernel/FirmwareKit/EFI/API.h b/dev/kernel/FirmwareKit/EFI/API.h new file mode 100644 index 00000000..b05fcc71 --- /dev/null +++ b/dev/kernel/FirmwareKit/EFI/API.h @@ -0,0 +1,107 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef __EFI_API__ +#define __EFI_API__ + +#include <FirmwareKit/EFI/EFI.h> +#include <FirmwareKit/Handover.h> +#include <KernelKit/MSDOS.h> +#include <KernelKit/PE.h> + +#define kNeWebsiteMacro "https://aker.com/help" +#define kNeKernelSubsystem (StrLen(kNeWebsiteMacro)) + +#ifdef __BOOTZ__ +// forward decl. +class BootTextWriter; + +#define __BOOTKIT_NO_INCLUDE__ 1 + +#include <BootKit/BootKit.h> +#include <modules/CoreGfx/FBMgr.h> +#endif // ifdef __BOOTZ__ + +inline EfiSystemTable* ST = nullptr; +inline EfiBootServices* BS = nullptr; + +EXTERN_C void rt_cli(); +EXTERN_C void rt_hlt(); + +namespace EFI +{ + /// @brief Halt and clear interrupts. + /// @return + inline Void Stop() noexcept + { + while (YES) + { + rt_cli(); + rt_hlt(); + } + } + + /** +@brief Exit EFI API to let the OS load correctly. +Bascially frees everything we have in the EFI side. +*/ + inline void ExitBootServices(UInt64 MapKey, EfiHandlePtr ImageHandle) noexcept + { + if (!ST) + return; + + ST->BootServices->ExitBootServices(ImageHandle, MapKey); + } + + inline UInt32 Platform() noexcept + { + return kPeMachineAMD64; + } + + /*** + * @brief Throw an error, stop execution as well. + * @param ErrorCode error code to be print. + * @param Reason reason to be print. + */ + inline void ThrowError(const EfiCharType* ErrorCode, + const EfiCharType* Reason) noexcept + { + ST->ConOut->OutputString(ST->ConOut, L"\r*** STOP ***\r"); + + ST->ConOut->OutputString(ST->ConOut, L"*** ERROR: "); + ST->ConOut->OutputString(ST->ConOut, ErrorCode); + + ST->ConOut->OutputString(ST->ConOut, L" ***\r *** REASON: "); + ST->ConOut->OutputString(ST->ConOut, Reason); + + ST->ConOut->OutputString(ST->ConOut, L" ***\r"); + + EFI::Stop(); + } +} // namespace EFI + +inline void InitEFI(EfiSystemTable* SystemTable) noexcept +{ + if (!SystemTable) + return; + + ST = SystemTable; + BS = ST->BootServices; + + ST->ConOut->ClearScreen(SystemTable->ConOut); + ST->ConOut->SetAttribute(SystemTable->ConOut, kEFIYellow); + + ST->BootServices->SetWatchdogTimer(0, 0, 0, nullptr); + ST->ConOut->EnableCursor(ST->ConOut, false); +} + +#ifdef __BOOTZ__ + +#include <BootKit/Platform.h> + +#endif // ifdef __BOOTZ__ + +#endif /* ifndef __EFI_API__ */ diff --git a/dev/kernel/FirmwareKit/EFI/EFI.h b/dev/kernel/FirmwareKit/EFI/EFI.h new file mode 100644 index 00000000..ff97f7d6 --- /dev/null +++ b/dev/kernel/FirmwareKit/EFI/EFI.h @@ -0,0 +1,936 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef FIRMWARE_KIT_EFI_H +#define FIRMWARE_KIT_EFI_H + +/** +@brief Implementation of the main EFI protocols. +*/ + +#include <NewKit/Defines.h> + +using namespace NeOS; + +/* we always use stdcall in EFI, the pascal way of calling functions. */ + +#ifndef EPI_API +#define EFI_API __attribute__((ms_abi)) +#endif // ifndef EPI_API + +#define IN +#define OUT +#define OPTIONAL + +#define EFI_FINAL final + +// Forward decls + +struct EfiTableHeader; +struct EfiLoadFileProtocol; +struct EfiSimpleTextOutputProtocol; +struct EfiDevicePathProtocol; +struct EfiBootServices; +struct EfiMemoryDescriptor; +struct EfiSystemTable; +struct EfiGUID; +struct EfiFileDevicePathProtocol; +struct EfiHandle; +struct EfiGraphicsOutputProtocol; +struct EfiBitmask; +struct EfiFileProtocol; +struct EfiSimpleTextInputProtocol; + +typedef UInt64 EfiStatusType; + +typedef Char16 EfiChar16Type; + +/// @brief Core Handle Kind +/// Self is like NT's Win32 HANDLE type. +typedef struct EfiHandle +{ +} * EfiHandlePtr; + +/* UEFI uses wide characters by default. */ +typedef WideChar EfiCharType; + +typedef UInt64 EfiPhysicalAddress; +typedef UIntPtr EfiVirtualAddress; + +/// What's BootBolicy? +/// If TRUE, indicates that the request originates from the boot manager, and +/// that the boot manager is attempting to load FilePath as a boot selection. If +/// FALSE, then FilePath must match an exact file to be loaded. + +typedef UInt64(EFI_API* EfiTextString)(struct EfiSimpleTextOutputProtocol* Self, + const WideChar* OutputString); + +typedef UInt64(EFI_API* EfiTextAttrib)(struct EfiSimpleTextOutputProtocol* Self, + const WideChar Attribute); + +typedef UInt64(EFI_API* EfiTextClear)(struct EfiSimpleTextOutputProtocol* Self); + +typedef UInt64(EFI_API* EfiLoadFile)(EfiLoadFileProtocol* Self, + EfiFileDevicePathProtocol* FilePath, + Boolean BootPolicy, + UInt32* BufferSize, + VoidPtr Buffer); + +typedef UInt64(EFI_API* EfiCopyMem)(VoidPtr DstBuf, VoidPtr SrcBuf, SizeT Length); + +typedef UInt64(EFI_API* EfiSetMem)(VoidPtr DstBuf, Char Byte, SizeT Length); + +typedef UInt64(EFI_API* EfiHandleProtocol)(EfiHandlePtr Handle, EfiGUID* Guid, VoidPtr* Device); + +typedef UInt64(EFI_API* EfiLocateDevicePath)(EfiGUID* Protocol, + EfiDevicePathProtocol** DevicePath, + EfiHandlePtr Device); + +typedef UInt64(EFI_API* EfiStartImage)(EfiHandlePtr Handle, VoidPtr ArgsSize, VoidPtr ArgsPtr); + +typedef UInt64(EFI_API* EfiLoadImage)(Boolean BootPolicy, + EfiHandlePtr ParentHandle, + EfiFileDevicePathProtocol* DeviceFile, + VoidPtr buffer, + SizeT size, + EfiHandlePtr* ppHandle); + +/// EFI pool helpers, taken from iPXE. + +typedef enum EfiMemoryType +{ + /// + /// Not used. + /// + EfiReservedMemoryType, + /// + /// The code portions of a loaded application. + /// (Note that UEFI OS loaders are UEFI applications.) + /// + EfiLoaderCode, + /// + /// The data portions of a loaded application and the default data allocation + /// type used by an application to allocate pool memory. + /// + EfiLoaderData, + /// + /// The code portions of a loaded Boot Services Driver. + /// + EfiBootServicesCode, + /// + /// The data portions of a loaded Boot Serves Driver, and the default data + /// allocation type used by a Boot Services Driver to allocate pool memory. + /// + EfiBootServicesData, + /// + /// The code portions of a loaded Runtime Services Driver. + /// + EfiRuntimeServicesCode, + /// + /// The data portions of a loaded Runtime Services Driver and the default + /// data allocation type used by a Runtime Services Driver to allocate pool + /// memory. + /// + EfiRuntimeServicesData, + /// + /// Free (unallocated) memory. + /// + EfiConventionalMemory, + /// + /// Memory in which errors have been detected. + /// + EfiUnusableMemory, + /// + /// Memory that holds the ACPI tables. + /// + EfiACPIReclaimMemory, + /// + /// Address space reserved for use by the firmware. + /// + EfiACPIMemoryNVS, + /// + /// Used by system firmware to request that a memory-mapped IO region + /// be mapped by the OS to a virtual address so it can be accessed by EFI + /// runtime services. + /// + EfiMemoryMappedIO, + /// + /// System memory-mapped IO region that is used to translate memory + /// cycles to IO cycles by the processor. + /// + EfiMemoryMappedIOPortSpace, + /// + /// Address space reserved by the firmware for code that is part of the + /// processor. + /// + EfiPalCode, + /// + /// A memory region that operates as EfiConventionalMemory, + /// however it happens to also support byte-addressable non-volatility. + /// + EfiPersistentMemory, + /// + /// A memory region that describes system memory that has not been accepted + /// by a corresponding call to the underlying isolation architecture. + /// + EfiUnacceptedMemoryType, + /// + /// The last type of memory. + /// Not a real type. + /// + EfiMaxMemoryType, +} EfiMemoryType; + +typedef enum EfiAllocateType +{ + /// Anything that satisfy the request. + AllocateAnyPages, + AllocateMaxAddress, + /// + /// Allocate pages at a specified address. + /// + AllocateAddress, + /// + /// Maximum enumeration value that may be used for bounds checking. + /// + MaxAllocateType +} EfiAllocateType; + +typedef struct EfiMemoryDescriptor +{ + /// + /// Kind of the memory region. + /// Kind EFI_MEMORY_TYPE is defined in the + /// AllocatePages() function description. + /// + UInt32 Kind; + /// + /// Physical address of the first byte in the memory region. PhysicalStart + /// must be aligned on a 4 KiB boundary, and must not be above + /// 0xfffffffffffff000. Kind EFI_PHYSICAL_ADDRESS is defined in the + /// AllocatePages() function description + /// + EfiPhysicalAddress PhysicalStart; + /// + /// Virtual address of the first byte in the memory region. + /// VirtualStart must be aligned on a 4 KiB boundary, + /// and must not be above 0xfffffffffffff000. + /// + EfiVirtualAddress VirtualStart; + /// + /// NumberOfPages Number of 4 KiB pages in the memory region. + /// NumberOfPages must not be 0, and must not be any value + /// that would represent a memory page with a start address, + /// either physical or virtual, above 0xfffffffffffff000. + /// + UInt64 NumberOfPages; + /// + /// Attributes of the memory region that describe the bit mask of capabilities + /// for that memory region, and not necessarily the current settings for that + /// memory region. + /// + UInt64 Attribute; +} EfiMemoryDescriptor; + +typedef UInt64(EFI_API* EfiAllocatePool)(EfiMemoryType PoolType, UInt32 Size, VoidPtr* Buffer); + +typedef UInt64(EFI_API* EfiFreePool)(VoidPtr Buffer); + +typedef UInt64(EFI_API* EfiCalculateCrc32)(VoidPtr Data, UInt32 DataSize, UInt32* CrcOut); + +/** +@brief Present in every header, used to identify a UEFI structure. +*/ +typedef struct EfiTableHeader +{ + UInt64 Signature; + UInt32 Revision; + UInt32 HeaderSize; + UInt32 Crc32; + UInt32 Reserved; +} EfiTableHeader; + +#define EFI_ACPI_TABLE_PROTOCOL_GUID \ + { \ + 0xffe06bdd, 0x6107, 0x46a6, \ + { \ + 0x7b, 0xb2, 0x5a, 0x9c, 0x7e, 0xc5, 0x27, 0x5c \ + } \ + } + +#define EFI_LOAD_FILE_PROTOCOL_GUID \ + { \ + 0x56EC3091, 0x954C, 0x11d2, \ + { \ + 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b \ + } \ + } + +#define EFI_LOAD_FILE2_PROTOCOL_GUID \ + { \ + 0x4006c0c1, 0xfcb3, 0x403e, \ + { \ + 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d \ + } \ + } + +#define EFI_LOADED_IMAGE_PROTOCOL_GUID \ + { \ + 0x5B1B31A1, 0x9562, 0x11d2, \ + { \ + 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B \ + } \ + } + +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ + { \ + 0x9042a9de, 0x23dc, 0x4a38, \ + { \ + 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a \ + } \ + } + +#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000 + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + { \ + 0x0964e5b22, 0x6459, 0x11d2, \ + { \ + 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b \ + } \ + } + +#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ + { \ + 0xbc62157e, 0x3e33, 0x4fec, \ + { \ + 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf \ + } \ + } + +#define EFI_DEVICE_PATH_PROTOCOL_GUID \ + { \ + 0x9576e91, 0x6d3f, 0x11d2, \ + { \ + 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b \ + } \ + } + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + { \ + 0x0964e5b22, 0x6459, 0x11d2, \ + { \ + 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b \ + } \ + } + +typedef UInt64(EfiImageUnload)(EfiHandlePtr ImageHandle); + +enum +{ + kPixelRedGreenBlueReserved8BitPerColor, + kPixelBlueGreenRedReserved8BitPerColor, + kPixelBitMask, + kPixelBltOnly, + kPixelFormatMax +}; + +typedef struct EfiBitmask +{ + UInt32 RedMask; + UInt32 GreenMask; + UInt32 BlueMask; + UInt32 ReservedMask; +} EfiBitmask; + +typedef struct +{ + UInt8 Blue; + UInt8 Green; + UInt8 Red; + UInt8 Reserved; +} EfiGraphicsOutputBltPixel; + +typedef enum EfiGraphicsOutputProtocolBltOperation +{ + EfiBltVideoFill, + EfiBltVideoToBltBuffer, + EfiBltBufferToVideo, + EfiBltVideoToVideo, + EfiGraphicsOutputBltOperationMax +} EfiGraphicsOutputProtocolBltOperation; + +typedef struct EfiGraphicsOutputProtocolModeInformation +{ + UInt32 Version; + UInt32 HorizontalResolution; + UInt32 VerticalResolution; + UInt32 PixelFormat; + EfiBitmask PixelInformation; + UInt32 PixelsPerScanLine; +} EfiGraphicsOutputProtocolModeInformation; + +typedef UInt64(EFI_API* EfiGraphicsOutputProtocolQueryMode)( + EfiGraphicsOutputProtocol* Self, UInt32 ModeNumber, UInt32* SizeOfInfo, EfiGraphicsOutputProtocolModeInformation** Info); + +typedef UInt64(EFI_API* EfiGraphicsOutputProtocolSetMode)( + EfiGraphicsOutputProtocol* Self, UInt32 ModeNumber); + +typedef UInt64(EFI_API* EfiGraphicsOutputProtocolBlt)( + EfiGraphicsOutputProtocol* Self, EfiGraphicsOutputBltPixel* BltBuffer, EfiGraphicsOutputProtocolBltOperation BltOperation, UInt32 SourceX, UInt32 SourceY, UInt32 DestinationX, UInt32 DestinationY, UInt32 Width, UInt32 Height, UInt32 Delta); + +typedef struct +{ + UInt32 MaxMode; + UInt32 Mode; + EfiGraphicsOutputProtocolModeInformation* Info; + UInt32 SizeOfInfo; + UIntPtr FrameBufferBase; + UInt32 FrameBufferSize; +} EfiGraphicsOutputProtocolMode; + +typedef struct EfiGraphicsOutputProtocol +{ + EfiGraphicsOutputProtocolQueryMode QueryMode; + EfiGraphicsOutputProtocolSetMode SetMode; + EfiGraphicsOutputProtocolBlt Blt; + EfiGraphicsOutputProtocolMode* Mode; +} EfiGraphicsOutputProtocol; + +typedef struct EfiLoadImageProtocol +{ + UInt32 Revision; + EfiHandlePtr ParentHandle; + EfiSystemTable* SystemTable; + + // Source location of the image + EfiHandlePtr DeviceHandle; + EfiDevicePathProtocol* FilePath; + Void* Reserved; + + // Image’s load options + UInt32 LoadOptionsSize; + Void* LoadOptions; + + // Location where image was loaded + Void* ImageBase; + UInt64 ImageSize; + EfiMemoryType ImageCodeType; + EfiMemoryType ImageDataType; + EfiImageUnload Unload; +} EfiLoadImageProtocol; + +typedef struct EfiLoadFileProtocol +{ + EfiLoadFile LoadFile; +} EfiLoadFileProtocol; + +typedef struct EfiDevicePathProtocol +{ + UInt8 Kind; + UInt8 SubType; + UInt8 Length[2]; +} EfiDevicePathProtocol; + +typedef struct EfiFileDevicePathProtocol +{ + EfiDevicePathProtocol Proto; + + /// + /// File Path of this struct + /// + WideChar Path[kPathLen]; +} EfiFileDevicePathProtocol; + +typedef UInt64(EFI_API* EfiExitBootServices)(VoidPtr ImageHandle, + UInt32 MapKey); + +typedef UInt64(EFI_API* EfiAllocatePages)(EfiAllocateType AllocType, + EfiMemoryType MemType, + UInt32 Count, + EfiPhysicalAddress* Memory); + +typedef UInt64(EFI_API* EfiFreePages)(EfiPhysicalAddress* Memory, UInt32 Pages); + +typedef UInt64(EFI_API* EfiGetMemoryMap)(UInt32* MapSize, + EfiMemoryDescriptor* DescPtr, + UInt32* MapKey, + UInt32* DescSize, + UInt32* DescVersion); + +/** + * @brief GUID type, something you can also find in CFKit. + */ +typedef struct EfiGUID EFI_FINAL +{ + UInt32 Data1; + UInt16 Data2; + UInt16 Data3; + UInt8 Data4[8]; +} EfiGUID; + +/*** + * Protocol stuff... + */ + +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ + { \ + 0x387477c1, 0x69c7, 0x11d2, \ + { \ + 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b \ + } \ + } + +/** some helpers */ +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +typedef UInt64(EFI_API* EfiLocateProtocol)(EfiGUID* Protocol, + VoidPtr Registration, + VoidPtr* Interface); + +typedef UInt64(EFI_API* EfiOpenProtocol)(EfiHandlePtr Handle, EfiGUID* Guid, VoidPtr* Interface, EfiHandlePtr AgentHandle, EfiHandlePtr ControllerHandle, UInt32 Attributes); + +typedef UInt64(EFI_API* EfiEnableCursor)(EfiSimpleTextOutputProtocol* Self, Boolean Visible); + +/** +@name EfiBootServices +@brief UEFI Boot Services record, it contains functions necessary to a +firmware level application. +*/ +typedef struct EfiBootServices +{ + EfiTableHeader SystemTable; + VoidPtr RaiseTPL; + VoidPtr RestoreTPL; + EfiAllocatePages AllocatePages; + EfiFreePages FreePages; + EfiGetMemoryMap GetMemoryMap; + EfiAllocatePool AllocatePool; + EfiFreePool FreePool; + VoidPtr CreateEvent; + VoidPtr SetTimer; + VoidPtr WaitForEvent; + VoidPtr SignalEvent; + VoidPtr CloseEvent; + VoidPtr CheckEvent; + VoidPtr InstallProtocolInterface; + VoidPtr ReinstallProtocolInterface; + VoidPtr UninstallProtocolInterface; + EfiHandleProtocol HandleProtocol; + VoidPtr Reserved; + VoidPtr RegisterProtocolNotify; + VoidPtr LocateHandle; + EfiLocateDevicePath LocateDevicePath; + VoidPtr InstallConfigurationTable; + EfiLoadImage LoadImage; + EfiStartImage StartImage; + VoidPtr Exit; + VoidPtr UnloadImage; + EfiExitBootServices ExitBootServices; + VoidPtr GetNextMonotonicCount; + VoidPtr Stall; + EfiStatusType(EFI_API* SetWatchdogTimer)(UInt32 Timeout, UInt64 WatchdogCode, UInt32 DataSize, EfiCharType* Data); + VoidPtr ConnectController; + VoidPtr DriveonnectController; + EfiOpenProtocol OpenProtocol; + VoidPtr CloseProtocol; + VoidPtr OpenProtocolInformation; + VoidPtr ProtocolsPerHandle; + VoidPtr LocateHandleBuffer; + EfiLocateProtocol LocateProtocol; + VoidPtr InstallMultipleProtocolInterfaces; + VoidPtr UninstallMultipleProtocolInterfaces; + EfiCalculateCrc32 CalculateCrc32; + EfiCopyMem CopyMem; + EfiSetMem SetMem; + VoidPtr CreateEventEx; +} EfiBootServices; + +#define kEntireDevPath 0xFF +#define kThisInstancePath 0x01 + +/** +@brief PrintF like protocol. +*/ +typedef struct EfiSimpleTextOutputProtocol +{ + VoidPtr Reset; + EfiTextString OutputString; + VoidPtr TestString; + VoidPtr QueryMode; + VoidPtr SetMode; + EfiTextAttrib SetAttribute; + EfiTextClear ClearScreen; + VoidPtr SetCursorPosition; + EfiEnableCursor EnableCursor; + VoidPtr Mode; +} EfiSimpleTextOutputProtocol; + +typedef struct +{ + UInt16 ScanCode; + EfiChar16Type UnicodeChar; +} EfiInputKey; + +typedef EfiStatusType(EFI_API* EfiInputReadKey)( + IN EfiSimpleTextInputProtocol* This, + OUT EfiInputKey* Key); + +typedef EfiStatusType(EFI_API* EfiInputReset)( + IN EfiSimpleTextInputProtocol* This, + IN Boolean ExtendedChk); + +typedef EfiStatusType(EFI_API* EfiWaitForEvent)( + IN UInt32 NumberOfEvents, + IN VoidPtr Event, + OUT UInt32* Index); + +typedef struct EfiSimpleTextInputProtocol +{ + EfiInputReset Reset; + EfiInputReadKey ReadKeyStroke; + EfiWaitForEvent WaitForKey; +} EfiSimpleTextInputProtocol; + +/// @biref Open Volume procedure ptr. +typedef UInt64(EFI_API* EfiOpenVolume)(struct EfiSimpleFilesystemProtocol*, + struct EfiFileProtocol**); + +struct EfiSimpleFilesystemProtocol +{ + UInt64 Revision; + EfiOpenVolume OpenVolume; +}; + +typedef struct EfiRuntimeServices +{ + EfiTableHeader SystemTable; + VoidPtr GetTime, SetTime, GetWakeupTime, SetWakeupTime, SetVirtualAddressMap, ConvertPointer; + UInt64(EFI_API* GetVariable)(const WideChar* Name, EfiGUID VendorGUID, UInt32* Attributes, UInt32* DataSize, VoidPtr Data); + VoidPtr GetNextVariable; + UInt64(EFI_API* SetVariable)(const WideChar* Name, EfiGUID VendorGUID, UInt32* Attributes, UInt32* DataSize, VoidPtr Data); + VoidPtr GetNextHighMonotonicCount; + VoidPtr ResetSystem; + VoidPtr UpdateCapsule; + VoidPtr QueryCapsuleCapabilites; + VoidPtr QueryVariableInfo; +} EfiRuntimeServices; + +/** +@brief The Structure that they give you when booting. +*/ +typedef struct EfiSystemTable +{ + EfiTableHeader SystemHeader; + WideChar* FirmwareVendor; + UInt32 FirmwareRevision; + EfiHandlePtr ConsoleInHandle; + EfiSimpleTextInputProtocol* ConIn; + EfiHandlePtr ConsoleOutHandle; + EfiSimpleTextOutputProtocol* ConOut; + EfiHandlePtr StandardErrorHandle; + VoidPtr StdErr; + EfiRuntimeServices* RuntimeServices; + EfiBootServices* BootServices; + UInt64 NumberOfTableEntries; + /// The configuration table (contains the RSD PTR entry.) + struct + { + EfiGUID VendorGUID; + VoidPtr VendorTable; + } * ConfigurationTable; +} EfiSystemTable; + +#define kEfiOk 0 +#define kEfiFail -1 +#define kBufferTooSmall 5 + +#define EFI_EXTERN_C extern "C" + +typedef struct EfiIPV4 +{ + UInt8 Addr[4]; +} EfiIPV4; + +/// +/// 16-byte buffer. An IPv6 internet protocol address. +/// +typedef struct EfiIPV6 +{ + UInt8 Addr[16]; +} EfiIPV6; + +#define kEFIYellow (0x01 | 0x02 | 0x04 | 0x08) + +#ifdef __x86_64 +#define __EFI_x86_64__ 1 +#endif // __x86_64 + +enum +{ + kEFIHwDevicePath = 0x01, + kEFIAcpiDevicePath = 0x02, + kEFIMessaingDevicePath = 0x03, + kEFIMediaDevicePath = 0x04, + kEFIBiosBootPath = 0x05, + kEFIEndOfPath = 0x06, + kEFICount = 6, +}; + +#define END_DEVICE_PATH_TYPE 0x7f +#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xFF +#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 + +#define kEfiOffsetOf(T, F) __builtin_offsetof(T, F) + +/// File I/O macros + +#define kEFIFileRead 0x0000000000000001 +#define kEFIFileWrite 0x0000000000000002 +#define kEFIFileCreate 0x0000000000000000 + +#define kEFIReadOnly 0x01 +#define kEFIHidden 0x02 +#define kEFISystem 0x04 +#define kEFIReserved 0x08 +#define kEFIDirectory 0x10 +#define kEFIArchive 0x20 + +#define EFI_FILE_PROTOCOL_REVISION 0x00010000 +#define EFI_FILE_PROTOCOL_REVISION2 0x00020000 +#define EFI_FILE_PROTOCOL_LATEST_REVISION EFI_FILE_PROTOCOL_REVISION2 + +#define EFI_EXTRA_DESCRIPTOR_SIZE 8 + +#define EFI_MP_SERVICES_PROTOCOL_GUID \ + { \ + 0x3fdda605, 0xa76e, 0x4f46, \ + { \ + 0xad, 0x29, 0x12, 0xf4, \ + 0x53, 0x1b, 0x3d, 0x08 \ + } \ + } + +#define PROCESSOR_AS_BSP_BIT 0x00000001 +#define PROCESSOR_ENABLED_BIT 0x00000002 +#define PROCESSOR_HEALTH_STATUS_BIT 0x00000004 + +#define END_OF_CPU_LIST 0xffffffff + +typedef struct EfiIOToken +{ + // + // If Event is NULL, then blocking I/O is performed. + // If Event is not NULL and non-blocking I/O is supported, then non-blocking + // I/O is performed, and Event will be signaled when the read request is + // completed. The caller must be prepared to handle the case where the + // callback associated with Event occurs before the original asynchronous I/O + // request call returns. + // + UInt64 Event; + + // + // Defines whether or not the signaled event encountered an error. + // + UInt64 Status; + + // + // For OpenEx(): Not Used, ignored. + // For ReadEx(): On input, the size of the Buffer. On output, the amount of + // data returned in Buffer. + // In both cases, the size is measured in bytes. + // For WriteEx(): On input, the size of the Buffer. On output, the amount of + // data actually written. + // In both cases, the size is measured in bytes. + // For FlushEx(): Not used, ignored. + // + UInt32 BufferSize; + + // + // For OpenEx(): Not Used, ignored. + // For ReadEx(): The buffer into which the data is read. + // For WriteEx(): The buffer of data to write. + // For FlushEx(): Not Used, ignored. + // + Void* Buffer; +} EfiIOToken; + +typedef struct EfiFileProtocol +{ + UInt64 Revision; + + EfiStatusType(EFI_API* Open)(struct EfiFileProtocol* Self, + struct EfiFileProtocol** Out, + EfiCharType* CharType, + UInt64 OpenMode, + UInt64 Attrib); + + EfiStatusType(EFI_API* Close)(struct EfiFileProtocol* Self); + + EfiStatusType(EFI_API* Delete)(struct EfiFileProtocol* Self); + + EfiStatusType(EFI_API* Read)(struct EfiFileProtocol* Self, UInt64* BufSize, VoidPtr BufOut); + + EfiStatusType(EFI_API* Write)(struct EfiFileProtocol* Self, UInt64* BufSize, VoidPtr BufOut); + + EfiStatusType(EFI_API* GetPosition)(EfiFileProtocol* Self, UInt64* Position); + + EfiStatusType(EFI_API* SetPosition)(EfiFileProtocol* Self, UInt64* Position); + + EfiStatusType(EFI_API* GetInfo)(struct EfiFileProtocol*, struct EfiGUID*, UInt32*, void*); + + EfiStatusType(EFI_API* SetInfo)(struct EfiFileProtocol*, struct EfiGUID*, UInt32*, void*); + + EfiStatusType(EFI_API* Flush)(EfiFileProtocol*); + + EfiStatusType(EFI_API* OpenEx)(EfiFileProtocol* Self, + EfiFileProtocol** OutHandle, + EfiCharType* Path, + UInt64 Mode, + UInt64 Attrib, + struct EfiIOToken* Token); + + EfiStatusType(EFI_API* ReadEx)(EfiFileProtocol* Self, + struct EfiIOToken* Token); + + EfiStatusType(EFI_API* WriteEx)(EfiFileProtocol* Self, + struct EfiIOToken* Token); + + EfiStatusType(EFI_API* FlushEx)(EfiFileProtocol* Self, + struct EfiIOToken* Token); +} EfiFileProtocol, *EfiFileProtocolPtr; + +typedef UInt64 EfiCursorType; + +typedef struct EfiTime +{ + UInt16 Year; + UInt8 Month; + UInt8 Day; + UInt8 Hour; + UInt8 Minute; + UInt8 Second; + UInt8 Pad1; + UInt32 Nanosecond; + Int16 TimeZone; + UInt8 Daylight; + UInt8 Pad2; +} EfiTime; + +#define EFI_FILE_INFO_GUID \ + { \ + 0x09576e92, 0x6d3f, 0x11d2, \ + { \ + 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b \ + } \ + } + +struct EfiFileInfo EFI_FINAL +{ + /// @brief Structure size. + UInt64 Size; + /// @brief File size. + UInt64 FileSize; + /// @brief Physical size on disk. + UInt64 PhysicalSize; + /// @brief Create time. + EfiTime CreateTime; + /// @brief Last access time. + EfiTime LastAccessTime; + /// @brief Edit time. + EfiTime EditTime; + /// @brief Attributes. + UInt64 Attribute; + /// @brief VLA file name. + WideChar FileName[1]; +}; + +//******************************************************* +// EFI_CPU_PHYSICAL_LOCATION +// @note As in the EFI specs. +//******************************************************* +typedef struct _EfiCPUPhyiscalLocation +{ + UInt32 Package; + UInt32 Core; + UInt32 Thread; +} EfiCPUPhyiscalLocation; + +typedef union _EfiExtendedProcessorInformation { + EfiCPUPhyiscalLocation Location2; +} EfiExtendedProcessorInformation; + +typedef struct _EfiProcessorInformation +{ + UInt64 ProcessorId; + UInt32 StatusFlag; + EfiCPUPhyiscalLocation Location; + EfiExtendedProcessorInformation ExtendedInformation; +} EfiProcessorInformation; + +typedef EfiStatusType EFI_API (*EfiMpServicesGetNumberOfProcessors)( + IN struct _EfiMpServicesProtocol* Self, + OUT UInt32* NumberOfProcessors, + OUT UInt32* NumberOfEnabledProcessors); + +typedef EfiStatusType EFI_API (*EfiMpServicesGetProcessorInfo)( + IN struct _EfiMpServicesProtocol* Self, + IN UInt32* ProcessorNumber, + OUT struct _EfiProcessorInformation* NumberOfEnabledProcessors); + +typedef void EFI_API (*EFI_AP_PROCEDURE)( + IN VoidPtr ProcedureArgument); + +typedef EfiStatusType EFI_API (*EfiMpServicesStartupAllAPS)( + IN struct _EfiMpServicesProtocol* Self, + IN EFI_AP_PROCEDURE Procedure, + IN Boolean SingleThread, + IN VoidPtr WaitEvent OPTIONAL, // EFI_EVENT first, but unused here. + IN UInt32 TimeoutInMicroSeconds, + IN Void* ProcedureArgument OPTIONAL, + OUT UInt32** FailedCpuList OPTIONAL); + +typedef EfiStatusType EFI_API (*EfiMpServicesSwitchBSP)( + IN struct _EfiMpServicesProtocol* Self, + IN UInt32 ProcessorNumber, + IN Boolean EnableOldBSP); + +typedef EfiStatusType EFI_API (*EfiMpServicesStartupThisAP)( + IN struct _EfiMpServicesProtocol* Self, + IN EFI_AP_PROCEDURE Procedure, + IN UInt32 ProcessorNumber, + IN VoidPtr WaitEvent OPTIONAL, + IN UInt32 TimeoutInMicroseconds, + IN Void* ProcedureArgument OPTIONAL, + OUT Boolean* Finished OPTIONAL); + +typedef EfiStatusType EFI_API (*EfiMpServicesDisableThisAP)( + IN struct _EfiMpServicesProtocol* Self, + IN UInt32 ProcessorNumber, + IN Boolean EnableAP, + IN UInt32* HealthFlag OPTIONAL); + +typedef EfiStatusType EFI_API (*EfiMpServicesWhoAmI)( + IN struct _EfiMpServicesProtocol* Self, + OUT UInt32* ProcessorNumber); + +typedef struct _EfiMpServicesProtocol +{ + EfiMpServicesGetNumberOfProcessors GetNumberOfProcessors; + EfiMpServicesGetProcessorInfo GetProcessorInfo; + EfiMpServicesStartupAllAPS StartupAllAPs; + EfiMpServicesStartupThisAP StartupThisAP; + EfiMpServicesSwitchBSP SwitchBSP; + EfiMpServicesDisableThisAP EnableDisableAP; + EfiMpServicesWhoAmI WhoAmI; +} EfiMpServicesProtocol; + +#endif // ifndef FIRMWARE_KIT_EFI_H diff --git a/dev/kernel/FirmwareKit/EFI/NS.h b/dev/kernel/FirmwareKit/EFI/NS.h new file mode 100644 index 00000000..18da8aaa --- /dev/null +++ b/dev/kernel/FirmwareKit/EFI/NS.h @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace Firmware::Detail::EFI +{ + using namespace NeOS; + + EXTERN_C + { +#include <FirmwareKit/EFI/EFI.h> + } + +} // namespace Firmware::Detail::EFI diff --git a/dev/kernel/FirmwareKit/EPM.h b/dev/kernel/FirmwareKit/EPM.h new file mode 100644 index 00000000..4728e2f5 --- /dev/null +++ b/dev/kernel/FirmwareKit/EPM.h @@ -0,0 +1,111 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/** + @brief The Explicit Partition Map scheme. +*/ + +#ifndef FIRMWAREKIT_EPM_H +#define FIRMWAREKIT_EPM_H + +#include <NewKit/Defines.h> + +#define kEPMNameLength (32) +#define kEPMFilesystemLength (16) +#define kEPMMagicLength (5) + +/* @brief AMD64 magic for EPM */ +#define kEPMMagic86 "EPMAM" + +/* @brief RISC-V magic for EPM */ +#define kEPMMagicRISCV "EPMRV" + +/* @brief ARM magic for EPM */ +#define kEPMMagicARM "EPMAR" + +/* @brief 64x0 magic for EPM */ +#define kEPMMagic64k "EPM64" + +/* @brief 32x0 magic for EPM */ +#define kEPMMagic32k "EPM32" + +/* @brief POWER magic for EPM */ +#define kEPMMagicPPC "EPMPC" + +/* @brief Invalid magic for EPM */ +#define kEPMMagicError "EPM??" + +#ifdef __NE_AMD64__ +#define kEPMMagic kEPMMagic86 +#else +#ifdef __NE_ARM64__ +#define kEPMMagic kEPMMagicARM +#else +#define kEPMMagic kEPMMagicError +#endif +#endif + +///! @brief partition must start at this address. +///! Anything below is reserved for Data backup by the Main OS. +#define kEPMPartBlockLba (sizeof(EPM_PART_BLOCK)) + +///! @brief Current EPM revision. +#define kEPMRevisionBcd (0x0100) + +/// !@brief EPM boot block address. +#define kEPMBootBlockLba (0U) + +#define kEPMReserveLen (399) + +struct EPM_GUID; +struct EPM_PART_BLOCK; + +/* The first 0 > 128 addresses of a disk contains these headers. */ + +/// @brief EPM GUID structure. +typedef struct EPM_GUID +{ + NeOS::UInt32 Data1; + NeOS::UInt16 Data2; + NeOS::UInt16 Data3; + NeOS::UInt8 Data4[8]; +} PACKED EPM_GUID; + +/** + * @brief The EPM boot block. + * @note NumBlock and LbaStart are ignored on some platforms. + */ +struct PACKED EPM_PART_BLOCK +{ + NeOS::Char Magic[kEPMMagicLength]; + NeOS::Char Name[kEPMNameLength]; + EPM_GUID Guid; + NeOS::Int32 Version; + NeOS::Int64 NumBlocks; + NeOS::Int64 SectorSz; + NeOS::Int64 LbaStart; // base offset + NeOS::Int64 LbaEnd; // end offset + NeOS::Int16 Kind; + NeOS::Int16 Flags; + NeOS::Int32 FsVersion; + NeOS::Char Fs[kEPMFilesystemLength]; /* NeFS, HeFS... */ + NeOS::Char Reserved[kEPMReserveLen]; // to fill a full sector. +}; + +///! @brief Version kind enum. +///! @brief Use in boot block version field. + +enum +{ + kEPMInvalid = 0x00, + kEPMGenericOS = 0xcf, // Generic OS + kEPMLinux = 0x8f, // Linux on EPM + kEPMBSD = 0x9f, // Berkeley Soft. Distribution + kEPMNeOS = 0x1f, // This OS. + kEPMInvalidOS = 0xff, +}; + +#endif // ifndef FIRMWAREKIT_EPM_H diff --git a/dev/kernel/FirmwareKit/GPT.h b/dev/kernel/FirmwareKit/GPT.h new file mode 100644 index 00000000..91838bc7 --- /dev/null +++ b/dev/kernel/FirmwareKit/GPT.h @@ -0,0 +1,57 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <FirmwareKit/EFI/EFI.h> + +#define kSectorSizeGPT (512U) + +namespace NeOS +{ + struct GPT_GUID; + struct GPT_PARTITION_TABLE; + struct GPT_PARTITION_ENTRY; + + /// @brief GPT GUID structure. + typedef struct GPT_GUID + { + NeOS::UInt32 Data1; + NeOS::UInt16 Data2; + NeOS::UInt16 Data3; + NeOS::UInt8 Data4[8]; + } GPT_GUID; + + struct PACKED GPT_PARTITION_TABLE final + { + Char PartitionName[8]; + UInt32 Revision; + UInt32 HeaderSize; + UInt32 ChecksumCRC32; + UInt32 Reserved1; + UInt64 LBAHeader; + UInt64 LBAAltHeader; + UInt64 FirstGPTEntry; + UInt64 LastGPTEntry; + GPT_GUID Guid; + UInt64 StartingLBA; + UInt32 NumPartitionEntries; + UInt32 SizeOfEntries; + UInt32 CRC32PartEntry; + UInt8 Reserved2[kSectorSizeGPT]; + }; + + struct PACKED GPT_PARTITION_ENTRY + { + GPT_GUID PartitionTypeGUID; + GPT_GUID UniquePartitionGUID; + UInt64 StartLBA; + UInt64 EndLBA; + UInt64 Attributes; + UInt8 Name[72]; + }; +} // namespace NeOS diff --git a/dev/kernel/FirmwareKit/Handover.h b/dev/kernel/FirmwareKit/Handover.h new file mode 100644 index 00000000..4ff681ed --- /dev/null +++ b/dev/kernel/FirmwareKit/Handover.h @@ -0,0 +1,108 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/** + * @file Handover.h + * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com) + * @brief The handover boot protocol. + * @version 1.15 + * @date 2024-02-23 + * + * @copyright Copyright (c) 2024, Amlal EL Mahrouss + * + */ + +#pragma once + +#include <NewKit/Defines.h> + +#define kHandoverMagic 0xBADCC +#define kHandoverVersion 0x0117 + +/* Initial bitmap pointer location and size. */ +#define kHandoverBitMapSz (gib_cast(4)) +#define kHandoverStructSz sizeof(HEL::BootInfoHeader) + +namespace NeOS::HEL +{ + /** + @brief The executable type enum. + */ + enum + { + kTypeKernel = 100, + kTypeKernelDriver = 101, + kTypeRsrc = 102, + kTypeInvalid = 103, + kTypeCount = 4, + }; + + /** + @brief The executable architecture enum. + */ + + enum + { + kArchAMD64 = 122, + kArchARM64 = 123, + kArchRISCV = 124, + kArchCount = 3, + }; + + struct BootInfoHeader final + { + UInt64 f_Magic; + UInt64 f_Version; + + VoidPtr f_BitMapStart; + SizeT f_BitMapSize; + + VoidPtr f_PageStart; + + VoidPtr f_KernelImage; + SizeT f_KernelSz; + VoidPtr f_StartupImage; + SizeT f_StartupSz; + + WideChar f_FirmwareVendorName[32]; + SizeT f_FirmwareVendorLen; + + VoidPtr f_FirmwareCustomTables[2]; // On EFI 0: BS 1: ST + + struct + { + VoidPtr f_SmBios; + VoidPtr f_VendorPtr; + VoidPtr f_MpPtr; + Bool f_MultiProcessingEnabled; + } f_HardwareTables; + + struct + { + UIntPtr f_The; + SizeT f_Size; + UInt32 f_Width; + UInt32 f_Height; + UInt32 f_PixelFormat; + UInt32 f_PixelPerLine; + } f_GOP; + + UInt64 f_FirmwareSpecific[8]; + }; + + enum + { + kHandoverSpecificKind, + kHandoverSpecificAttrib, + kHandoverSpecificMemoryEfi, + }; + + /// @brief Alias of bootloader main type. + typedef Int32 (*HandoverProc)(BootInfoHeader* boot_info); +} // namespace NeOS::HEL + +/// @brief Bootloader information header global variable. +inline NeOS::HEL::BootInfoHeader* kHandoverHeader = nullptr; diff --git a/dev/kernel/HALKit/.gitkeep b/dev/kernel/HALKit/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/.gitkeep diff --git a/dev/kernel/HALKit/AMD64/CPUID.h b/dev/kernel/HALKit/AMD64/CPUID.h new file mode 100644 index 00000000..7f04ac27 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/CPUID.h @@ -0,0 +1,86 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: CPUID.h + Purpose: CPUID flags. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +enum CPUFeatureEnum +{ + kCPUFeatureSSE3 = 1 << 0, + kCPUFeaturePCLMUL = 1 << 1, + kCPUFeatureDTES64 = 1 << 2, + kCPUFeatureMONITOR = 1 << 3, + kCPUFeatureDS_CPL = 1 << 4, + kCPUFeatureVMX = 1 << 5, + kCPUFeatureSMX = 1 << 6, + kCPUFeatureEST = 1 << 7, + kCPUFeatureTM2 = 1 << 8, + kCPUFeatureSSSE3 = 1 << 9, + kCPUFeatureCID = 1 << 10, + kCPUFeatureSDBG = 1 << 11, + kCPUFeatureFMA = 1 << 12, + kCPUFeatureCX16 = 1 << 13, + kCPUFeatureXTPR = 1 << 14, + kCPUFeaturePDCM = 1 << 15, + kCPUFeaturePCID = 1 << 17, + kCPUFeatureDCA = 1 << 18, + kCPUFeatureSSE4_1 = 1 << 19, + kCPUFeatureSSE4_2 = 1 << 20, + kCPUFeatureX2APIC = 1 << 21, + kCPUFeatureMOVBE = 1 << 22, + kCPUFeaturePOP3C = 1 << 23, + kCPUFeatureECXTSC = 1 << 24, + kCPUFeatureAES = 1 << 25, + kCPUFeatureXSAVE = 1 << 26, + kCPUFeatureOSXSAVE = 1 << 27, + kCPUFeatureAVX = 1 << 28, + kCPUFeatureF16C = 1 << 29, + kCPUFeatureRDRAND = 1 << 30, + kCPUFeatureHYPERVISOR = 1 << 31, + kCPUFeatureFPU = 1 << 0, + kCPUFeatureVME = 1 << 1, + kCPUFeatureDE = 1 << 2, + kCPUFeaturePSE = 1 << 3, + kCPUFeatureEDXTSC = 1 << 4, + kCPUFeatureMSR = 1 << 5, + kCPUFeaturePAE = 1 << 6, + kCPUFeatureMCE = 1 << 7, + kCPUFeatureCX8 = 1 << 8, + kCPUFeatureAPIC = 1 << 9, + kCPUFeatureSEP = 1 << 11, + kCPUFeatureMTRR = 1 << 12, + kCPUFeaturePGE = 1 << 13, + kCPUFeatureMCA = 1 << 14, + kCPUFeatureCMOV = 1 << 15, + kCPUFeaturePAT = 1 << 16, + kCPUFeaturePSE36 = 1 << 17, + kCPUFeaturePSN = 1 << 18, + kCPUFeatureCLFLUSH = 1 << 19, + kCPUFeatureDS = 1 << 21, + kCPUFeatureACPI = 1 << 22, + kCPUFeatureMMX = 1 << 23, + kCPUFeatureFXSR = 1 << 24, + kCPUFeatureSSE = 1 << 25, + kCPUFeatureSSE2 = 1 << 26, + kCPUFeatureSS = 1 << 27, + kCPUFeatureHTT = 1 << 28, + kCPUFeatureTM = 1 << 29, + kCPUFeatureIA64 = 1 << 30, + kCPUFeaturePBE = 1 << 31 +}; + +namespace NeOS +{ + typedef Int64 CPUID; +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc b/dev/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc new file mode 100644 index 00000000..f327dc3f --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalACPIFactoryInterface.cc @@ -0,0 +1,122 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <HALKit/AMD64/Processor.h> +#include <NewKit/KString.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/MemoryMgr.h> + +namespace NeOS +{ + namespace Detail + { + struct FADT final : public SDT + { + UInt32 FirmwareCtrl; + UInt32 Dsdt; + + // field used in ACPI 1.0; no longer in use, for compatibility only + UInt8 Reserved; + + UInt8 PreferredPowerManagementProfile; + UInt16 SCI_Interrupt; + UInt32 SMI_CommandPort; + UInt8 AcpiEnable; + UInt8 AcpiDisable; + UInt8 S4BIOS_REQ; + UInt8 PSTATE_Control; + UInt32 PM1aEventBlock; + UInt32 PM1bEventBlock; + UInt32 PM1aControlBlock; + UInt32 PM1bControlBlock; + UInt32 PM2ControlBlock; + UInt32 PMTimerBlock; + UInt32 GPE0Block; + UInt32 GPE1Block; + UInt8 PM1EventLength; + UInt8 PM1ControlLength; + UInt8 PM2ControlLength; + UInt8 PMTimerLength; + UInt8 GPE0Length; + UInt8 GPE1Length; + UInt8 GPE1Base; + UInt8 CStateControl; + UInt16 WorstC2Latency; + UInt16 WorstC3Latency; + UInt16 FlushSize; + UInt16 FlushStride; + UInt8 DutyOffset; + UInt8 DutyWidth; + UInt8 DayAlarm; + UInt8 MonthAlarm; + UInt8 Century; + + // reserved in ACPI 1.0; used since ACPI 2.0+ + UInt16 BootArchitecturkMMFlags; + + UInt8 Reserved2; + UInt32 Flags; + + // 12 byte structure; see below for details + ACPI_ADDRESS ResetReg; + + UInt8 ResetValue; + UInt8 Reserved3[3]; + + // 64bit pointers - Available on ACPI 2.0+ + UInt64 X_FirmwareControl; + UInt64 X_Dsdt; + + ACPI_ADDRESS X_PM1aEventBlock; + ACPI_ADDRESS X_PM1bEventBlock; + ACPI_ADDRESS X_PM1aControlBlock; + ACPI_ADDRESS X_PM1bControlBlock; + ACPI_ADDRESS X_PM2ControlBlock; + ACPI_ADDRESS X_PMTimerBlock; + ACPI_ADDRESS X_GPE0Block; + ACPI_ADDRESS X_GPE1Block; + }; + } // namespace Detail + + ACPIFactoryInterface::ACPIFactoryInterface(VoidPtr rsp_ptr) + : fRsdp(rsp_ptr), fEntries(0) + { + } + + Bool ACPIFactoryInterface::Shutdown() + { + failed_to_shutdown: + return NO; + } + + /// @brief Reboot machine in either ACPI or by triple faulting. + /// @return nothing it's a reboot. + Void ACPIFactoryInterface::Reboot() + { + failed_to_reboot: + asm volatile(".intel_syntax noprefix; " + "rt_reset_hardware:; " + "cli; " + "wait_gate1: ; " + "in al,0x64 ; " + "and al,2 ; " + "jnz wait_gate1 ; " + "mov al,0x0D1 ; " + "out 0x64,al ; " + "wait_gate2: ; " + "in al,0x64 ; " + "and al,2 ; " + "jnz wait_gate2 ; " + "mov al,0x0FE ; " + "out 0x60,al ; " + "xor rax,rax ; " + "lidt [rax] ; " + "reset_wait: ; " + "jmp reset_wait ; " + ".att_syntax; "); + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/HalAPICController.cc b/dev/kernel/HALKit/AMD64/HalAPICController.cc new file mode 100644 index 00000000..a4de5091 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalAPICController.cc @@ -0,0 +1,44 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <HALKit/AMD64/Processor.h> + +#define cIOAPICRegVal (4) +#define cIOAPICRegReg (0) + +namespace NeOS::HAL +{ + APICController::APICController(VoidPtr base) + : fApic(base) + { + } + + /// @brief Read from APIC controller. + /// @param reg register. + UInt32 APICController::Read(UInt32 reg) noexcept + { + MUST_PASS(this->fApic); + + UInt32 volatile* io_apic = (UInt32 volatile*)this->fApic; + io_apic[cIOAPICRegReg] = (reg & 0xFF); + + return io_apic[cIOAPICRegVal]; + } + + /// @brief Write to APIC controller. + /// @param reg register. + /// @param value value. + Void APICController::Write(UInt32 reg, UInt32 value) noexcept + { + MUST_PASS(this->fApic); + + UInt32 volatile* io_apic = (UInt32 volatile*)this->fApic; + + io_apic[cIOAPICRegReg] = (reg & 0xFF); + io_apic[cIOAPICRegVal] = value; + } +} // namespace NeOS::HAL diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc new file mode 100644 index 00000000..da680afa --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessor.cc @@ -0,0 +1,271 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <KernelKit/UserProcessScheduler.h> +#include <HALKit/AMD64/Processor.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/BinaryMutex.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/Timer.h> +#include <modules/CoreGfx/TextMgr.h> +#include <NewKit/KernelPanic.h> +#include <KernelKit/HardwareThreadScheduler.h> + +#define kApicSignature "APIC" + +#define kAPIC_ICR_Low 0x300 +#define kAPIC_ICR_High 0x310 +#define kAPIC_SIPI_Vector 0x00500 +#define kAPIC_EIPI_Vector 0x00400 + +#define kAPIC_BASE_MSR 0x1B +#define kAPIC_BASE_MSR_BSP 0x100 +#define kAPIC_BASE_MSR_ENABLE 0x800 + +/// @note: _hal_switch_context is internal + +/////////////////////////////////////////////////////////////////////////////////////// + +//! NOTE: fGSI stands 'Field Global System Interrupt' + +/////////////////////////////////////////////////////////////////////////////////////// + +namespace NeOS::HAL +{ + struct PROCESS_APIC_MADT; + struct PROCESS_CONTROL_BLOCK; + + struct PROCESS_CONTROL_BLOCK final + { + HAL::StackFramePtr mFrame; + }; + + STATIC struct PROCESS_APIC_MADT* kMADTBlock = nullptr; + STATIC Bool kSMPAware = false; + STATIC Int64 kSMPCount = 0; + + STATIC UIntPtr kApicBaseAddress = 0UL; + + STATIC Int32 kSMPInterrupt = 0; + STATIC UInt64 kAPICLocales[kSchedProcessLimitPerTeam] = {0}; + STATIC VoidPtr kRawMADT = nullptr; + + /// @brief Multiple APIC Descriptor Table. + struct PROCESS_APIC_MADT final SDT_OBJECT + { + UInt32 Address; // Madt address + UInt8 Flags; // Madt flags + + struct + { + UInt8 Type; + UInt8 Len; + + union { + struct + { + UInt8 IoID; + UInt8 Zero; + UInt32 IoAddress; + UInt32 GISBase; + } IOAPIC; + + struct + { + UInt8 Source; + UInt8 IRQSource; + UInt32 GSI; + UInt16 Flags; + } LApicNMI; + + struct + { + UInt8 ProcessorID; + UInt16 Flags; + UInt8 LINT; + } LAPIC; + + struct + { + UInt16 Reserved; + UInt64 Address; + } LApicOverride; + + struct + { + UInt16 Reserved; + UInt32 x2APICID; + UInt32 Flags; + UInt32 AcpiID; + } LApic; + }; + } List[]; // Records List + }; + + /////////////////////////////////////////////////////////////////////////////////////// + + /***********************************************************************************/ + /// @brief Send IPI command to APIC. + /// @param apic_id programmable interrupt controller id. + /// @param vector vector interrupt. + /// @param target target APIC adress. + /// @return + /***********************************************************************************/ + + Void hal_send_start_ipi(UInt32 target, UInt32 apic_id) + { + NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_High, apic_id << 24); + NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_Low, 0x00000500 | 0x00004000 | 0x00000000); + + while (NeOS::ke_dma_read<UInt32>(target, kAPIC_ICR_Low) & 0x1000) + { + ; + } + } + + /***********************************************************************************/ + /// @brief Send end IPI for CPU. + /// @param apic_id + /// @param vector + /// @param target + /// @return + /***********************************************************************************/ + Void hal_send_sipi(UInt32 target, UInt32 apic_id, UInt8 vector) + { + NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_High, apic_id << 24); + NeOS::ke_dma_write<UInt32>(target, kAPIC_ICR_Low, 0x00000600 | 0x00004000 | 0x00000000 | vector); + + while (NeOS::ke_dma_read<UInt32>(target, kAPIC_ICR_Low) & 0x1000) + { + NE_UNUSED(0); + } + } + + STATIC PROCESS_CONTROL_BLOCK kProcessBlocks[kSchedProcessLimitPerTeam] = {0}; + + EXTERN_C HAL::StackFramePtr mp_get_current_context(Int64 pid) + { + const auto process_index = pid % kSchedProcessLimitPerTeam; + return kProcessBlocks[process_index].mFrame; + } + + EXTERN_C BOOL mp_register_process(HAL::StackFramePtr stack_frame, ProcessID pid) + { + MUST_PASS(stack_frame); + + const auto process_index = pid % kSchedProcessLimitPerTeam; + + kProcessBlocks[process_index].mFrame = stack_frame; + + auto first_id = kAPICLocales[0]; + + hal_send_sipi(kApicBaseAddress, first_id, (UInt8)(((UIntPtr)stack_frame->BP) >> 12)); + + return YES; + } + + /***********************************************************************************/ + /// @brief Is the current config SMP aware? + /// @return True if YES, False if not. + /***********************************************************************************/ + Bool mp_is_smp(Void) noexcept + { + return kSMPAware; + } + + /***********************************************************************************/ + /// @brief Assembly symbol to bootstrap AP. + /***********************************************************************************/ + EXTERN_C Char* hal_ap_blob_start; + + /***********************************************************************************/ + /// @brief Assembly symbol to bootstrap AP. + /***********************************************************************************/ + EXTERN_C Char* hal_ap_blob_end; + + /***********************************************************************************/ + /// @brief Fetch and enable SMP scheduler. + /// @param vendor_ptr SMP containing structure. + /***********************************************************************************/ + Void mp_get_cores(VoidPtr vendor_ptr) noexcept + { + if (!vendor_ptr) + return; + + if (!kHandoverHeader->f_HardwareTables.f_MultiProcessingEnabled) + { + kSMPAware = NO; + return; + } + + auto hw_and_pow_int = PowerFactoryInterface(vendor_ptr); + kRawMADT = hw_and_pow_int.Find(kApicSignature).Leak().Leak(); + + kMADTBlock = reinterpret_cast<PROCESS_APIC_MADT*>(kRawMADT); + kSMPAware = NO; + + if (kMADTBlock) + { + SizeT index = 0; + + kSMPInterrupt = 0; + kSMPCount = 0; + + kout << "SMP: Starting APs...\r"; + + UInt32 eax, edx; + kApicBaseAddress = kMADTBlock->Address; + + while (Yes) + { + if (kMADTBlock->List[index].Type > 9 || + kSMPCount > kSchedProcessLimitPerTeam) + break; + + switch (kMADTBlock->List[index].Type) + { + case 0x00: { + if (kMADTBlock->List[kSMPCount].LAPIC.ProcessorID < 1) + break; + + kAPICLocales[kSMPCount] = kMADTBlock->List[kSMPCount].LAPIC.ProcessorID; + kout << "SMP: APIC ID: " << number(kAPICLocales[kSMPCount]) << kendl; + + // I'll just make the AP start from scratch here. + + hal_send_start_ipi(kApicBaseAddress, kAPICLocales[kSMPCount]); + + HardwareTimer timer(NeOS::rtl_ms(10)); + timer.Wait(); + + /// TODO: HAL helper to create an address. + + hal_send_sipi(kApicBaseAddress, kAPICLocales[kSMPCount], (UInt8)(((UIntPtr)hal_ap_blob_start) >> 12)); + + ++kSMPCount; + break; + } + default: + break; + } + + ++index; + } + + kout << "SMP: number of APs: " << number(kSMPCount) << kendl; + + // Kernel is now SMP aware. + // That means that the scheduler is now available (on MP Kernels) + + kSMPAware = true; + + /// TODO: Notify Boot AP that it must start. + } + } +} // namespace NeOS::HAL + +/////////////////////////////////////////////////////////////////////////////////////// diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessorGNU.s b/dev/kernel/HALKit/AMD64/HalApplicationProcessorGNU.s new file mode 100644 index 00000000..a8ad3b76 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessorGNU.s @@ -0,0 +1,8 @@ +.data + +.global hal_ap_blob_start /* Export the start symbol */ +.global hal_ap_blob_end /* Export the end symbol */ + +hal_ap_blob_start: + .incbin "HALKit/AMD64/HalApplicationProcessorStartup.bin" +hal_ap_blob_end: diff --git a/dev/kernel/HALKit/AMD64/HalApplicationProcessorStartup.asm b/dev/kernel/HALKit/AMD64/HalApplicationProcessorStartup.asm new file mode 100644 index 00000000..c64e0a09 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalApplicationProcessorStartup.asm @@ -0,0 +1,77 @@ +;; /* +;; * ======================================================== +;; * +;; * NeKernel +;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. +;; * +;; * ======================================================== +;; */ + +[bits 16] +[org 0x7c000] + +hal_ap_start: + mov ax, 0x0 + mov ss, ax + mov esp, 0x7000 + + cli + mov eax, cr0 + or eax, 1 + mov cr0, eax + jmp .hal_ap_start_flush +.hal_ap_start_flush: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + mov eax, cr4 + or eax, 1 << 5 + mov cr4, eax + + mov eax, cr3 + mov cr3, eax + + mov ecx, 0xC0000080 + rdmsr + or eax, 1 + wrmsr + + mov eax, cr0 + or eax, (1 << 31) + mov cr0, eax + + jmp 0x08:hal_ap_64bit_entry +hal_ap_end: + +hal_ap_length: + dq hal_ap_end - hal_ap_start + +[bits 64] + +hal_ap_64bit_entry: + mov ax, 0x23 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov rsp, [hal_ap_64bit_entry_stack_end] + + push 0x33 + push qword [hal_ap_64bit_entry_loop] + o64 pushf + push rsp + push 0x33 + + o64 iret + +hal_ap_64bit_entry_loop: + jmp $ + +hal_ap_64bit_entry_stack: + resb 8196*2 +hal_ap_64bit_entry_stack_end:
\ No newline at end of file diff --git a/dev/kernel/HALKit/AMD64/HalBoot.asm b/dev/kernel/HALKit/AMD64/HalBoot.asm new file mode 100644 index 00000000..3ccdd50e --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalBoot.asm @@ -0,0 +1,28 @@ +;; /* +;; * ======================================================== +;; * +;; * NeKernel +;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. +;; * +;; * ======================================================== +;; */ + +[bits 64] + +;; Global symbol of this unit +[extern hal_init_platform] + +%define kTypeKernel 100 +%define kArchAmd64 122 +%define kHandoverMagic 0xBADCC + +section .ldr + +HandoverMagic: + dq kHandoverMagic +HandoverType: + dw kTypeKernel +HandoverPad: + dw 0 +HandoverArch: + dw kArchAmd64 diff --git a/dev/kernel/HALKit/AMD64/HalCommonAPI.asm b/dev/kernel/HALKit/AMD64/HalCommonAPI.asm new file mode 100644 index 00000000..671a955b --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalCommonAPI.asm @@ -0,0 +1,82 @@ +;; /* +;; * ======================================================== +;; * +;; * NeKernel +;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. +;; * +;; * ======================================================== +;; */ + +section .text + +extern rt_wait_400ns + +global rt_out8 +global rt_out16 +global rt_out32 + +global rt_in8 +global rt_in16 +global rt_in32 + +rt_out8: + mov al, dl + mov dx, cx + out dx, al + ret + +rt_out16: + mov ax, dx + mov dx, cx + out dx, ax + ret + +rt_out32: + mov eax, edx + mov edx, ecx + out dx, eax + ret + +rt_in8: + mov dx, cx + in al, dx + ret + +rt_in16: + mov edx, ecx + in ax, dx + ret + +rt_in32: + mov rdx, rcx + in eax, dx + ret + +extern hal_system_call_enter +global mp_system_call_handler + +mp_system_call_handler: + + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + jmp hal_system_call_enter + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + + o64 sysret + +[bits 16] diff --git a/dev/kernel/HALKit/AMD64/HalControlRegister.s b/dev/kernel/HALKit/AMD64/HalControlRegister.s new file mode 100644 index 00000000..b94744f5 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalControlRegister.s @@ -0,0 +1,45 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +.globl hal_write_cr3 +.globl hal_write_cr0 +.globl hal_read_cr2 +.globl hal_read_cr3 +.globl hal_read_cr0 +.globl hal_flush_tlb +.globl hal_invl_tlb + +.text + +hal_invl_tlb: + invlpg (%rcx) + retq + +hal_flush_tlb: + call hal_read_cr3 + mov %rax, %rcx + call hal_write_cr3 + retq + +hal_read_cr3: + movq %cr3, %rax + retq + +hal_read_cr0: + movq %cr0, %rax + retq + +hal_read_cr2: + movq %cr2, %rax + retq + +hal_write_cr3: + movq %rcx, %cr3 + retq + +hal_write_cr0: + movq %rcx, %cr0 + retq diff --git a/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc new file mode 100644 index 00000000..9eaa24eb --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cc @@ -0,0 +1,245 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/UserProcessScheduler.h> +#include <NewKit/KString.h> +#include <SignalKit/Signals.h> + +STATIC BOOL kIsScheduling = NO; + +/// @brief Handle GPF fault. +/// @param rsp +EXTERN_C void idt_handle_gpf(NeOS::UIntPtr rsp) +{ + auto process = NeOS::UserProcessScheduler::The().CurrentProcess(); + + if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning) + return; + + kIsScheduling = NO; + + kout << "Kernel: General Protection Fault.\r"; + + process.Leak().ProcessSignal.SignalArg = rsp; + process.Leak().ProcessSignal.SignalID = SIGKILL; + process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status; + + kout << "Kernel: SIGKILL status.\r"; + + process.Leak().Status = NeOS::ProcessStatusKind::kKilled; + + process.Leak().Crash(); +} + +/// @brief Handle page fault. +/// @param rsp +EXTERN_C void idt_handle_pf(NeOS::UIntPtr rsp) +{ + auto process = NeOS::UserProcessScheduler::The().CurrentProcess(); + + if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning) + return; + + kIsScheduling = NO; + + kout << "Kernel: Page Fault.\r"; + kout << "Kernel: SIGKILL\r"; + + process.Leak().ProcessSignal.SignalArg = rsp; + process.Leak().ProcessSignal.SignalID = SIGKILL; + process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status; + + process.Leak().Status = NeOS::ProcessStatusKind::kKilled; + + process.Leak().Crash(); +} + +namespace NeOS::Detail +{ + constexpr static Int32 kTimeoutCount = 100000UL; +} + +/// @brief Handle scheduler interrupt. +EXTERN_C void idt_handle_scheduler(NeOS::UIntPtr rsp) +{ + static NeOS::Int64 try_count_before_brute = NeOS::Detail::kTimeoutCount; + + while (kIsScheduling) + { + --try_count_before_brute; + + if (try_count_before_brute < 1) + break; + } + + try_count_before_brute = NeOS::Detail::kTimeoutCount; + kIsScheduling = YES; + + NeOS::UserProcessHelper::StartScheduling(); + + kIsScheduling = NO; +} + +/// @brief Handle math fault. +/// @param rsp +EXTERN_C void idt_handle_math(NeOS::UIntPtr rsp) +{ + auto process = NeOS::UserProcessScheduler::The().CurrentProcess(); + + if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning) + return; + + kIsScheduling = NO; + + kout << "Kernel: Math error (division by zero?).\r"; + + process.Leak().ProcessSignal.SignalArg = rsp; + process.Leak().ProcessSignal.SignalID = SIGKILL; + process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status; + + kout << "Kernel: SIGKILL status.\r"; + + process.Leak().Status = NeOS::ProcessStatusKind::kKilled; + + process.Leak().Crash(); +} + +/// @brief Handle any generic fault. +/// @param rsp +EXTERN_C void idt_handle_generic(NeOS::UIntPtr rsp) +{ + auto process = NeOS::UserProcessScheduler::The().CurrentProcess(); + + if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning) + { + kout << "Getting here.\r"; + return; + } + + kIsScheduling = NO; + + kout << "Kernel: Generic Process Fault.\r"; + + process.Leak().ProcessSignal.SignalArg = rsp; + process.Leak().ProcessSignal.SignalID = SIGKILL; + process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status; + + kout << "Kernel: SIGKILL status.\r"; + + process.Leak().Status = NeOS::ProcessStatusKind::kKilled; + + process.Leak().Crash(); +} + +EXTERN_C NeOS::Void idt_handle_breakpoint(NeOS::UIntPtr rip) +{ + auto process = NeOS::UserProcessScheduler::The().CurrentProcess(); + + if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning) + { + kout << "Kernel: SIGTRAP\r"; + + while (YES) + ; + } + + kIsScheduling = NO; + + kout << "Kernel: Process RIP: " << NeOS::hex_number(rip) << kendl; + kout << "Kernel: SIGTRAP\r"; + + process.Leak().ProcessSignal.SignalArg = rip; + process.Leak().ProcessSignal.SignalID = SIGTRAP; + + process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status; + + kout << "Kernel: SIGTRAP status.\r"; + + process.Leak().Status = NeOS::ProcessStatusKind::kFrozen; +} + +/// @brief Handle #UD fault. +/// @param rsp +EXTERN_C void idt_handle_ud(NeOS::UIntPtr rsp) +{ + auto process = NeOS::UserProcessScheduler::The().CurrentProcess(); + + if (process.Leak().Status != NeOS::ProcessStatusKind::kRunning) + return; + + kIsScheduling = NO; + + kout << "Kernel: Undefined Opcode.\r"; + + process.Leak().ProcessSignal.SignalArg = rsp; + process.Leak().ProcessSignal.SignalID = SIGKILL; + process.Leak().ProcessSignal.PreviousStatus = process.Leak().Status; + + kout << "Kernel: SIGKILL status.\r"; + + process.Leak().Status = NeOS::ProcessStatusKind::kKilled; + + process.Leak().Crash(); +} + +/// @brief Enter syscall from assembly. +/// @param stack the stack pushed from assembly routine. +/// @return nothing. +EXTERN_C NeOS::Void hal_system_call_enter(NeOS::UIntPtr rcx_syscall_index, NeOS::UIntPtr rdx_syscall_struct) +{ + if (rcx_syscall_index < kSyscalls.Count()) + { + kout << "syscall: Enter Syscall.\r"; + + if (kSyscalls[rcx_syscall_index].fHooked) + { + if (kSyscalls[rcx_syscall_index].fProc) + { + (kSyscalls[rcx_syscall_index].fProc)((NeOS::VoidPtr)rdx_syscall_struct); + } + else + { + kout << "syscall: syscall isn't valid at all! (is nullptr)\r"; + } + } + else + { + kout << "syscall: syscall isn't hooked at all! (is set to false)\r"; + } + + kout << "syscall: Exit Syscall.\r"; + } +} + +/// @brief Enter Kernel call from assembly (DDK only). +/// @param stack the stack pushed from assembly routine. +/// @return nothing. +EXTERN_C NeOS::Void hal_kernel_call_enter(NeOS::UIntPtr rcx_kerncall_index, NeOS::UIntPtr rdx_kerncall_struct) +{ + if (rcx_kerncall_index < kKerncalls.Count()) + { + kout << "kerncall: Enter Kernel Call List.\r"; + + if (kKerncalls[rcx_kerncall_index].fHooked) + { + if (kKerncalls[rcx_kerncall_index].fProc) + { + (kKerncalls[rcx_kerncall_index].fProc)((NeOS::VoidPtr)rdx_kerncall_struct); + } + else + { + kout << "kerncall: Kernel call isn't valid at all! (is nullptr)\r"; + } + } + else + { + kout << "kerncall: Kernel call isn't hooked at all! (is set to false)\r"; + } + + kout << "kerncall: Exit Kernel Call List.\r"; + } +} diff --git a/dev/kernel/HALKit/AMD64/HalCoreSystemCalls.cc b/dev/kernel/HALKit/AMD64/HalCoreSystemCalls.cc new file mode 100644 index 00000000..75eb1f15 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalCoreSystemCalls.cc @@ -0,0 +1,5 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal EL Mahrouss, all rights reserved. + + ------------------------------------------- */ diff --git a/dev/kernel/HALKit/AMD64/HalDebugOutput.cc b/dev/kernel/HALKit/AMD64/HalDebugOutput.cc new file mode 100644 index 00000000..2bc89a5e --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalDebugOutput.cc @@ -0,0 +1,190 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/DebugOutput.h> +#include <NewKit/Utils.h> +#include <NewKit/New.h> +#include <modules/CoreGfx/FBMgr.h> +#include <modules/CoreGfx/TextMgr.h> + +namespace NeOS +{ + enum CommStatus : UInt16 + { + kStateInvalid, + kStateReady = 0xCF, + kStateTransmit = 0xFC, + kStateCnt = 3 + }; + + namespace Detail + { + constexpr const UInt16 kPort = 0x3F8; + static UInt16 kState = kStateInvalid; + + /// @brief Init COM1. + /// @return + template <Int16 PORT> + bool hal_serial_init() noexcept + { + if (kState == kStateReady || kState == kStateTransmit) + return true; + + HAL::rt_out8(PORT + 1, 0x00); // Disable all interrupts + HAL::rt_out8(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + HAL::rt_out8(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + HAL::rt_out8(PORT + 1, 0x00); // (hi byte) + HAL::rt_out8(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + HAL::rt_out8(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + HAL::rt_out8(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + HAL::rt_out8(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + HAL::rt_out8(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if + // serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if (HAL::rt_in8(PORT) != 0xAE) + { + return false; + } + + kState = kStateReady; + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + HAL::rt_out8(PORT + 4, 0x0F); + + return true; + } + } // namespace Detail + + TerminalDevice::~TerminalDevice() = default; + + EXTERN_C void ke_io_write(IDeviceObject<const Char*>* obj, const Char* bytes) + { +#ifdef __DEBUG__ + Detail::hal_serial_init<Detail::kPort>(); + + if (!bytes || Detail::kState != kStateReady) + return; + + if (*bytes == 0) + return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = rt_string_len(bytes, 256U); + + static int x = kFontSizeX, y = kFontSizeY; + + static BOOL not_important = YES; + + while (index < len) + { + if (bytes[index] == '\r') + HAL::rt_out8(Detail::kPort, '\r'); + + HAL::rt_out8(Detail::kPort, bytes[index] == '\r' ? '\n' : bytes[index]); + + char tmp_str[2]; + tmp_str[0] = bytes[index]; + tmp_str[1] = 0; + + if (bytes[index] == '*') + { + if (not_important) + not_important = NO; + else + not_important = YES; + + ++index; + + continue; + } + + fb_render_string(tmp_str, y, x, not_important ? RGB(0xff, 0xff, 0xff) : RGB(0x00, 0x00, 0xff)); + + if (bytes[index] == '\r') + { + y += kFontSizeY; + x = kFontSizeX; + } + + x += kFontSizeX; + + if (y > kHandoverHeader->f_GOP.f_Height) + { + y = kFontSizeY; + + fb_init(); + + FBDrawInRegion(fb_get_clear_clr(), FB::UIAccessibilty::Height(), FB::UIAccessibilty::Width(), + 0, 0); + + fb_clear(); + } + + ++index; + } + + Detail::kState = kStateReady; +#endif // __DEBUG__ + } + + EXTERN_C void ke_io_read(IDeviceObject<const Char*>*, const Char* bytes) + { +#ifdef __DEBUG__ + Detail::hal_serial_init<Detail::kPort>(); + + if (!bytes || Detail::kState != kStateReady) + return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + + ///! TODO: Look on how to wait for the UART to complete. + while (true) + { + auto in = HAL::rt_in8(Detail::kPort); + + ///! If enter pressed then break. + if (in == 0xD) + { + break; + } + + if (in < '0' || in < 'A' || in < 'a') + { + if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || + in != ':') + { + continue; + } + } + + ((char*)bytes)[index] = in; + + ++index; + } + + ((char*)bytes)[index] = 0; + + Detail::kState = kStateReady; +#endif // __DEBUG__ + } + + TerminalDevice TerminalDevice::The() noexcept + { + TerminalDevice out(NeOS::ke_io_write, NeOS::ke_io_read); + return out; + } + +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/HalDebugPort.cc b/dev/kernel/HALKit/AMD64/HalDebugPort.cc new file mode 100644 index 00000000..7eada646 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalDebugPort.cc @@ -0,0 +1,42 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +//! @file DebuggerPort.cc +//! @brief UART debug via packets. + +#include <ArchKit/ArchKit.h> +#include <KernelKit/DebugOutput.h> + +// after that we have start of additional data. + +namespace NeOS +{ + void rt_debug_listen(DebuggerPortHeader* theHook) noexcept + { + if (theHook == nullptr) + return; + + for (UInt32 i = 0U; i < kDebugMaxPorts; ++i) + { + HAL::rt_out16(theHook->fPort[i], kDebugMag0); + HAL::rt_wait_400ns(); + + HAL::rt_out16(theHook->fPort[i], kDebugMag1); + HAL::rt_wait_400ns(); + + HAL::rt_out16(theHook->fPort[i], kDebugMag2); + HAL::rt_wait_400ns(); + + HAL::rt_out16(theHook->fPort[i], kDebugMag3); + HAL::rt_wait_400ns(); + + if (HAL::rt_in16(theHook->fPort[i]) != kDebugUnboundPort) + ++theHook->fPortCnt; + + HAL::rt_wait_400ns(); + } + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/HalDescriptorLoader.cc b/dev/kernel/HALKit/AMD64/HalDescriptorLoader.cc new file mode 100644 index 00000000..154b11af --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalDescriptorLoader.cc @@ -0,0 +1,126 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <HALKit/AMD64/Processor.h> + +#define kPITDefaultTicks (1000U) + +namespace NeOS::HAL +{ + namespace Detail + { + STATIC ::NeOS::Detail::AMD64::InterruptDescriptorAMD64 + kInterruptVectorTable[kKernelIdtSize] = {}; + + STATIC void hal_set_irq_mask(UInt8 irql); + STATIC void hal_clear_irq_mask(UInt8 irql); + + STATIC Void hal_enable_pit(UInt16 ticks) noexcept + { + if (ticks == 0) + ticks = kPITDefaultTicks; + + // Configure PIT to receieve scheduler interrupts. + + UInt16 kPITCommDivisor = kPITFrequency / ticks; // 100 Hz. + + HAL::rt_out8(kPITControlPort, 0x36); // Command to PIT + HAL::rt_out8(kPITChannel0Port, kPITCommDivisor & 0xFF); // Send low byte + HAL::rt_out8(kPITChannel0Port, (kPITCommDivisor >> 8) & 0xFF); // Send high byte + + hal_clear_irq_mask(32); + } + + STATIC void hal_set_irq_mask(UInt8 irql) + { + UInt16 port; + UInt8 value; + + if (irql < 8) + { + port = kPICData; + } + else + { + port = kPIC2Data; + irql -= 8; + } + + value = rt_in8(port) | (1 << irql); + rt_out8(port, value); + } + + STATIC void hal_clear_irq_mask(UInt8 irql) + { + UInt16 port; + UInt8 value; + + if (irql < 8) + { + port = kPICData; + } + else + { + port = kPIC2Data; + irql -= 8; + } + + value = rt_in8(port) & ~(1 << irql); + rt_out8(port, value); + } + } // namespace Detail + + /// @brief Loads the provided Global Descriptor Table. + /// @param gdt + /// @return + Void GDTLoader::Load(RegisterGDT& gdt) + { + hal_load_gdt(gdt); + } + + Void IDTLoader::Load(Register64& idt) + { + rt_cli(); + + const Int16 kPITTickForScheduler = kPITDefaultTicks; + + volatile ::NeOS::UIntPtr** ptr_ivt = (volatile ::NeOS::UIntPtr**)idt.Base; + + for (SizeT idt_indx = 0; idt_indx < kKernelIdtSize; ++idt_indx) + { + Detail::kInterruptVectorTable[idt_indx].Selector = kIDTSelector; + Detail::kInterruptVectorTable[idt_indx].Ist = 0; + Detail::kInterruptVectorTable[idt_indx].TypeAttributes = kInterruptGate; + Detail::kInterruptVectorTable[idt_indx].OffsetLow = ((UIntPtr)ptr_ivt[idt_indx] & 0xFFFF); + Detail::kInterruptVectorTable[idt_indx].OffsetMid = (((UIntPtr)ptr_ivt[idt_indx] >> 16) & 0xFFFF); + Detail::kInterruptVectorTable[idt_indx].OffsetHigh = + (((UIntPtr)ptr_ivt[idt_indx] >> 32) & 0xFFFFFFFF); + + Detail::kInterruptVectorTable[idt_indx].Zero = 0; + } + + idt.Base = (UIntPtr)&Detail::kInterruptVectorTable[0]; + idt.Limit = sizeof(::NeOS::Detail::AMD64::InterruptDescriptorAMD64) * + (kKernelIdtSize); + + hal_load_idt(idt); + + Detail::hal_enable_pit(kPITTickForScheduler); + + rt_sti(); + } + + void GDTLoader::Load(Ref<RegisterGDT>& gdt) + { + GDTLoader::Load(gdt.Leak()); + } + + void IDTLoader::Load(Ref<Register64>& idt) + { + IDTLoader::Load(idt.Leak()); + } +} // namespace NeOS::HAL diff --git a/dev/kernel/HALKit/AMD64/HalInterruptAPI.asm b/dev/kernel/HALKit/AMD64/HalInterruptAPI.asm new file mode 100644 index 00000000..ffea6707 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalInterruptAPI.asm @@ -0,0 +1,402 @@ +;; /* +;; * --------------------------------------------------- +;; * +;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. +;; * +;; * File: HalInterruptAPI.asm +;; * Purpose: Interrupt API, redirect raw interrupts into their handlers. +;; * +;; * --------------------------------------------------- +;; */ + +[bits 64] + +%define kInterruptId 50 + +%macro IntExp 1 +global __NE_INT_%1 +__NE_INT_%1: + cld + + std + + o64 iret +%endmacro + +%macro IntNormal 1 +global __NE_INT_%1 +__NE_INT_%1: + cld + + std + + o64 iret +%endmacro + +; This file handles the core interrupt table +; Last edited 31/01/24 + +global ke_handle_irq +global kInterruptVectorTable + +extern idt_handle_gpf +extern idt_handle_pf +extern ke_io_write +extern idt_handle_ud +extern idt_handle_generic +extern idt_handle_breakpoint + +section .text + +__NE_INT_0: + cld + + mov al, 0x20 + out 0x20, al + + push rcx + call idt_handle_generic + pop rcx + + std + + o64 iret + +__NE_INT_1: + cld + + mov al, 0x20 + out 0x20, al + + push rcx + call idt_handle_generic + pop rcx + + std + + o64 iret + +__NE_INT_2: + cld + + mov al, 0x20 + out 0x20, al + + push rcx + call idt_handle_generic + pop rcx + + std + + o64 iret + +;; @brief Triggers a breakpoint and freeze the process. RIP is also fetched. +__NE_INT_3: + cld + + mov al, 0x20 + out 0x20, al + + push rcx + mov rcx, rsp + call idt_handle_generic + pop rcx + + std + + o64 iret + +__NE_INT_4: + cld + + mov al, 0x20 + out 0x20, al + + + push rcx + call idt_handle_generic + pop rcx + + std + + o64 iret + +__NE_INT_5: + cld + + mov al, 0x20 + out 0x20, al + + std + + o64 iret + +;; Invalid opcode interrupt +__NE_INT_6: + cld + + mov al, 0x20 + out 0x20, al + + push rcx + call idt_handle_generic + pop rcx + + std + + o64 iret + +__NE_INT_7: + cld + + mov al, 0x20 + out 0x20, al + + push rcx + call idt_handle_generic + pop rcx + + std + + o64 iret + +;; Invalid opcode interrupt +__NE_INT_8: + cld + + mov al, 0x20 + out 0xA0, al + out 0x20, al + + push rcx + call idt_handle_generic + pop rcx + + std + + o64 iret + +IntNormal 9 +IntExp 10 +IntExp 11 + +IntExp 12 + +__NE_INT_13: + cld + + mov al, 0x20 + out 0xA0, al + out 0x20, al + + push rcx + call idt_handle_gpf + pop rcx + + std + + o64 iret + +__NE_INT_14: + cld + + mov al, 0x20 + out 0xA0, al + out 0x20, al + + push rcx + call idt_handle_pf + pop rcx + + std + + o64 iret + +IntNormal 15 +IntNormal 16 +IntExp 17 +IntNormal 18 +IntNormal 19 +IntNormal 20 +IntNormal 21 + +IntNormal 22 + +IntNormal 23 +IntNormal 24 +IntNormal 25 +IntNormal 26 +IntNormal 27 +IntNormal 28 +IntNormal 29 +IntExp 30 +IntNormal 31 + +[extern idt_handle_scheduler] + +__NE_INT_32: + cld + + mov al, 0x20 + out 0xA0, al + out 0x20, al + + push rax + mov rcx, rsp + call idt_handle_scheduler + pop rax + + std + + o64 iret + +IntNormal 33 + +IntNormal 34 +IntNormal 35 +IntNormal 36 +IntNormal 37 +IntNormal 38 +IntNormal 39 +IntNormal 40 + +IntNormal 41 + +IntNormal 42 +IntNormal 43 +IntNormal 44 +IntNormal 45 +IntNormal 46 +IntNormal 47 +IntNormal 48 +IntNormal 49 + +[extern hal_system_call_enter] +[extern hal_kernel_call_enter] + +__NE_INT_50: + cld + + mov al, 0x20 + out 0xA0, al + out 0x20, al + + push rax + mov rax, hal_system_call_enter + + mov rcx, r8 + mov rdx, r9 + + call rax + pop rax + + std + + o64 iret + +__NE_INT_51: + cld + + mov al, 0x20 + out 0xA0, al + out 0x20, al + + push rax + mov rax, hal_kernel_call_enter + + mov rcx, r8 + mov rdx, r9 + + call rax + pop rax + + std + + o64 iret + +IntNormal 52 + +IntNormal 53 +IntNormal 54 +IntNormal 55 +IntNormal 56 +IntNormal 57 +IntNormal 58 +IntNormal 59 +IntNormal 60 + +%assign i 61 +%rep 195 + IntNormal i +%assign i i+1 +%endrep + +section .text + +[global hal_load_gdt] + +hal_load_gdt: + cld + + lgdt [rcx] + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + mov rax, 0x08 + push rax + push hal_reload_segments + + o64 retf + +extern hal_real_init + +hal_reload_segments: + std + jmp hal_real_init + ret + +global hal_load_idt + +hal_load_idt: + lidt [rcx] + + ; Master PIC initialization + mov al, 0x11 ; Start initialization in cascade mode + out 0x20, al ; Send initialization command to Master PIC + out 0xA0, al ; Send initialization command to Slave PIC + + ; Remap the PIC to use vectors 32-39 for Master and 40-47 for Slave + mov al, 0x20 ; Set Master PIC offset to 32 + out 0x21, al ; Send offset to Master PIC + + mov al, 0x28 ; Set Slave PIC offset to 40 + out 0xA1, al ; Send offset to Slave PIC + + ; Configure Master PIC to inform Slave PIC at IRQ2 + mov al, 0x04 ; Tell Master PIC there is a Slave PIC at IRQ2 + out 0x21, al + + ; Configure Slave PIC identity + mov al, 0x02 ; Tell Slave PIC its cascade identity + out 0xA1, al + + ; Set both PICs to 8086 mode + mov al, 0x01 ; 8086 mode + out 0x21, al + out 0xA1, al + + ret + +section .data + +kInterruptVectorTable: + %assign i 0 + %rep 256 + dq __NE_INT_%+i + %assign i i+1 + %endrep diff --git a/dev/kernel/HALKit/AMD64/HalKernelMain.cc b/dev/kernel/HALKit/AMD64/HalKernelMain.cc new file mode 100644 index 00000000..543e267b --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalKernelMain.cc @@ -0,0 +1,117 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/AHCI.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/HardwareThreadScheduler.h> +#include <KernelKit/CodeMgr.h> +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <NetworkKit/IPC.h> +#include <CFKit/Property.h> +#include <modules/CoreGfx/TextMgr.h> + +EXTERN_C NeOS::VoidPtr kInterruptVectorTable[]; +EXTERN_C NeOS::VoidPtr mp_user_switch_proc; +EXTERN_C NeOS::Char mp_user_switch_proc_stack_begin[]; + +STATIC NeOS::Void hal_init_scheduler_team() +{ + for (NeOS::SizeT i = 0U; i < NeOS::UserProcessScheduler::The().CurrentTeam().AsArray().Count(); ++i) + { + NeOS::UserProcessScheduler::The().CurrentTeam().AsArray()[i] = NeOS::UserProcess(); + NeOS::UserProcessScheduler::The().CurrentTeam().AsArray()[i].Status = NeOS::ProcessStatusKind::kKilled; + } +} + +STATIC NeOS::UInt64 hal_rdtsc_fn() +{ + NeOS::UInt32 lo, hi; + __asm__ volatile("rdtsc" + : "=a"(lo), "=d"(hi)); + + return ((NeOS::UInt64)hi << 32) | lo; +} + +STATIC NeOS::UInt64 kStartTim, kEndTim; + +/// @brief Kernel init procedure. +EXTERN_C void hal_init_platform( + NeOS::HEL::BootInfoHeader* handover_hdr) +{ + kStartTim = hal_rdtsc_fn(); + + kHandoverHeader = handover_hdr; + + if (kHandoverHeader->f_Magic != kHandoverMagic && + kHandoverHeader->f_Version != kHandoverVersion) + { + return; + } + + hal_init_scheduler_team(); + + /************************************** */ + /* INITIALIZE BIT MAP. */ + /************************************** */ + + kKernelBitMpSize = kHandoverHeader->f_BitMapSize; + kKernelBitMpStart = reinterpret_cast<NeOS::VoidPtr>( + reinterpret_cast<NeOS::UIntPtr>(kHandoverHeader->f_BitMapStart)); + + /************************************** */ + /* INITIALIZE GDT AND SEGMENTS. */ + /************************************** */ + + STATIC CONST auto kGDTEntriesCount = 6; + + /* GDT, mostly descriptors for user and kernel segments. */ + STATIC NeOS::HAL::Detail::NE_GDT_ENTRY ALIGN(0x08) kGDTArray[kGDTEntriesCount] = { + {.fLimitLow = 0, .fBaseLow = 0, .fBaseMid = 0, .fAccessByte = 0x00, .fFlags = 0x00, .fBaseHigh = 0}, // Null entry + {.fLimitLow = 0x0, .fBaseLow = 0, .fBaseMid = 0, .fAccessByte = 0x9A, .fFlags = 0xAF, .fBaseHigh = 0}, // Kernel code + {.fLimitLow = 0x0, .fBaseLow = 0, .fBaseMid = 0, .fAccessByte = 0x92, .fFlags = 0xCF, .fBaseHigh = 0}, // Kernel data + {.fLimitLow = 0x0, .fBaseLow = 0, .fBaseMid = 0, .fAccessByte = 0xFA, .fFlags = 0xAF, .fBaseHigh = 0}, // User code + {.fLimitLow = 0x0, .fBaseLow = 0, .fBaseMid = 0, .fAccessByte = 0xF2, .fFlags = 0xCF, .fBaseHigh = 0}, // User data + }; + + // Load memory descriptors. + NeOS::HAL::RegisterGDT gdt_reg; + + gdt_reg.Base = reinterpret_cast<NeOS::UIntPtr>(kGDTArray); + gdt_reg.Limit = (sizeof(NeOS::HAL::Detail::NE_GDT_ENTRY) * kGDTEntriesCount) - 1; + + FB::fb_clear_video(); + + //! GDT will load hal_read_init after it successfully loads the segments. + NeOS::HAL::GDTLoader gdt_loader; + gdt_loader.Load(gdt_reg); + + NeOS::ke_panic(RUNTIME_CHECK_BOOTSTRAP); +} + +EXTERN_C NeOS::Void hal_real_init(NeOS::Void) noexcept +{ + NeOS::NeFS::fs_init_nefs(); + + NeOS::HAL::mp_get_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr); + + NeOS::HAL::Register64 idt_reg; + + idt_reg.Base = (NeOS::UIntPtr)kInterruptVectorTable; + + NeOS::HAL::IDTLoader idt_loader; + + kEndTim = hal_rdtsc_fn(); + + kout << "Cycles Spent Before Userland: " << NeOS::number(kEndTim - kStartTim) << kendl; + + idt_loader.Load(idt_reg); + + while (YES) + { + continue; + } +} diff --git a/dev/kernel/HALKit/AMD64/HalKernelPanic.cc b/dev/kernel/HALKit/AMD64/HalKernelPanic.cc new file mode 100644 index 00000000..f0595903 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalKernelPanic.cc @@ -0,0 +1,68 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/KernelPanic.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/Timer.h> +#include <KernelKit/DebugOutput.h> +#include <NewKit/KString.h> +#include <FirmwareKit/Handover.h> +#include <KernelKit/FileMgr.h> +#include <modules/CoreGfx/FBMgr.h> +#include <modules/CoreGfx/TextMgr.h> +#include <NewKit/Utils.h> + +/* Each error code is attributed with an ID, which will prompt a string onto the + * screen. Wait for debugger... */ + +namespace NeOS +{ + /// @brief Dumping factory class. + class RecoveryFactory final + { + public: + STATIC Void Recover() noexcept; + }; + + /***********************************************************************************/ + /// @brief Stops execution of the kernel. + /// @param id kernel stop ID. + /***********************************************************************************/ + Void ke_panic(const NeOS::Int32& id, const Char* message) + { + fb_init(); + + auto panic_text = RGB(0xff, 0xff, 0xff); + + auto y = 10; + auto x = 10; + + kout << "Kernel_Panic_MSG: " << message << kendl; + kout << "Kernel_Panic_ID: " << hex_number(id) << kendl; + kout << "Kernel_Panic_CR2: " << hex_number((UIntPtr)hal_read_cr2()) << kendl; + + RecoveryFactory::Recover(); + } + + Void RecoveryFactory::Recover() noexcept + { + while (YES) + { + HAL::rt_halt(); + } + } + + void ke_runtime_check(bool expr, const Char* file, const Char* line) + { + if (!expr) + { + kout << "Kernel_Panic_File: " << file << kendl; + kout << "Kernel_Panic_Line: " << line << kendl; + + ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed + } + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc b/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc new file mode 100644 index 00000000..fe9f0421 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc @@ -0,0 +1,204 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: HalPagingMgr.cc + Purpose: Platform Paging Manager. + +------------------------------------------- */ + +#include <HALKit/AMD64/Paging.h> +#include <HALKit/AMD64/Processor.h> + +namespace NeOS::HAL +{ + typedef UInt32 PageTableIndex; + + /***********************************************************************************/ + /// \brief Page store type. + /***********************************************************************************/ + struct NE_PAGE_STORE final + { + struct + { + PDE* fPde{nullptr}; + PTE* fPte{nullptr}; + VoidPtr fPAddr{nullptr}; + } fInternalStore; + + Bool fStoreOp{No}; // Store operation is in progress. + + bool IsValidPage(PTE* pte) + { + return pte && pte->Present; + } + + bool IsWRPage(PTE* pte) + { + return pte && pte->Wr; + } + + bool IsUserPage(PTE* pte) + { + return pte && pte->User; + } + + static NE_PAGE_STORE& The() + { + static NE_PAGE_STORE the; + return the; + } + }; + + /// @brief Go over the Page structure and find the address of *virtual_address* + + UIntPtr hal_get_phys_address(VoidPtr virtual_address) + { + // Constants for table index bits + const UInt64 kPmlIndexMask = 0x1FFULL; // Mask for PML4, PDPT, PD, PT index (9 bits) + const UInt64 kPtIndexMask = 0xFFFULL; // Mask for page table index (12 bits) + + UInt64 cr3 = (UInt64)hal_read_cr3(); + + NE_PAGE_STORE& page_store = NE_PAGE_STORE::The(); + + // Extract the indices from the virtual address + UInt64 pml4_index = ((UIntPtr)virtual_address >> 39) & kPmlIndexMask; + UInt64 pdpt_index = ((UIntPtr)virtual_address >> 30) & kPmlIndexMask; + UInt64 pd_index = ((UIntPtr)virtual_address >> 21) & kPmlIndexMask; + UInt64 pt_index = ((UIntPtr)virtual_address >> 12) & kPmlIndexMask; + + page_store.fStoreOp = Yes; + + const auto kPmlEntrySize = 8; + + // Read the PML4 entry from memory + UInt64 pml4_base = cr3 & ~kPtIndexMask; // CR3 points to the PML4 table base, mask off lower bits + UInt64 pml4_entry = (pml4_base + pml4_index * kPmlEntrySize); // Each entry is 8 bytes + + // Read the PDPT entry + UInt64 pdpt_base = pml4_entry & ~kPtIndexMask; // Get the PDPT base physical address + UInt64 pdpt_entry = (pdpt_base + pdpt_index * kPmlEntrySize); + + // Read the PD entry + UInt64 pd_base = pdpt_entry & ~kPtIndexMask; // Get the Page Directory base physical address + UInt64 pd_entry = (pd_base + pd_index * kPmlEntrySize); + + // Read the PT entry + UInt64 pt_base = pd_entry & ~kPtIndexMask; // Get the Page Table base physical address + UInt64 pt_entry = (pt_base + pt_index * kPmlEntrySize); + + // Lastly, grab the pte entry. + NE_PDE* pde_struct = reinterpret_cast<NE_PDE*>(pt_base); + + return pde_struct->fEntries[pt_entry]->PhysicalAddress; + } + + /***********************************************************************************/ + /// \brief Retrieve the page status of a PTE. + /// \param pte Page Table Entry pointer. + /***********************************************************************************/ + STATIC Void mmi_page_status(PTE* pte) + { + kout << (pte->Present ? "Present" : "Not Present") << kendl; + kout << (pte->Wr ? "W/R" : "Not W/R") << kendl; + kout << (pte->ExecDisable ? "NX" : "Not NX") << kendl; + kout << (pte->User ? "User" : "Not User") << kendl; + } + + STATIC Int32 mmi_map_page_table_entry(UInt32 physical_address, UInt32 flags, NE_PTE* pt_entry, NE_PDE* pd_entry); + + /***********************************************************************************/ + /// @brief Maps or allocates a page from virtual_address. + /// @param virtual_address a valid virtual address. + /// @param phys_addr point to physical address. + /// @param flags the flags to put on the page. + /// @return Status code of page manipulation process. + /***********************************************************************************/ + EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags) + { + // Constants for table index bits + const UInt64 kPmlIndexMask = 0x1FFULL; // Mask for PML4, PDPT, PD, PT index (9 bits) + const UInt64 kPtIndexMask = 0xFFFULL; // Mask for page table index (12 bits) + + UInt64 cr3 = (UInt64)hal_read_cr3(); + + NE_PAGE_STORE& page_store = NE_PAGE_STORE::The(); + + // Extract the indices from the virtual address + UInt64 pml4_index = ((UIntPtr)virtual_address >> 39) & kPmlIndexMask; + UInt64 pdpt_index = ((UIntPtr)virtual_address >> 30) & kPmlIndexMask; + UInt64 pd_index = ((UIntPtr)virtual_address >> 21) & kPmlIndexMask; + UInt64 pt_index = ((UIntPtr)virtual_address >> 12) & kPmlIndexMask; + + page_store.fStoreOp = Yes; + + const auto kPmlEntrySize = 8; + + // Read the PML4 entry from memory + UInt64 pml4_base = cr3 & ~kPtIndexMask; // CR3 points to the PML4 table base, mask off lower bits + UInt64 pml4_entry = (pml4_base + pml4_index * kPmlEntrySize); // Each entry is 8 bytes + + // Read the PDPT entry + UInt64 pdpt_base = pml4_entry & ~kPtIndexMask; // Get the PDPT base physical address + UInt64 pdpt_entry = (pdpt_base + pdpt_index * kPmlEntrySize); + + // Read the PD entry + UInt64 pd_base = pdpt_entry & ~kPtIndexMask; // Get the Page Directory base physical address + UInt64 pd_entry = (pd_base + pd_index * kPmlEntrySize); + + // Read the PT entry + UInt64 pt_base = pd_entry & ~kPtIndexMask; // Get the Page Table base physical address + UInt64 pt_entry = (pt_base + pt_index * kPmlEntrySize); + + // Lastly, grab the pte entry. + NE_PDE* pde_struct = reinterpret_cast<NE_PDE*>(pt_base); + + return mmi_map_page_table_entry((UInt32)(UInt64)physical_address, flags, pde_struct->fEntries[pt_entry], pde_struct); + } + + /***********************************************************************************/ + /// @brief Maps flags for a specific pte. + /// @internal Internal function. + /***********************************************************************************/ + STATIC Int32 mmi_map_page_table_entry(UInt32 physical_address, UInt32 flags, NE_PTE* pt_entry, NE_PDE* pd_entry) + { + if (!pt_entry) + return 1; + + pt_entry->Present = true; + + if (flags & kMMFlagsWr) + pt_entry->Wr = true; + else if (flags & ~kMMFlagsWr) + pt_entry->Wr = false; + + if (flags & kMMFlagsNX) + pt_entry->ExecDisable = true; + else if (flags & ~kMMFlagsNX) + pt_entry->ExecDisable = false; + + if (flags & kMMFlagsUser) + pt_entry->User = true; + else if (flags & ~kMMFlagsUser) + pt_entry->User = false; + + pt_entry->PhysicalAddress = physical_address; + + hal_invl_tlb(reinterpret_cast<VoidPtr>(pt_entry)); + + mmi_page_status(pt_entry); + + NE_PAGE_STORE& page_store = NE_PAGE_STORE::The(); + + // Update Internal store. + + page_store.fInternalStore.fPde = pd_entry; + page_store.fInternalStore.fPte = pt_entry; + page_store.fInternalStore.fPAddr = (VoidPtr)(UIntPtr)physical_address; + + page_store.fStoreOp = No; + + return 0; + } +} // namespace NeOS::HAL diff --git a/dev/kernel/HALKit/AMD64/HalProcessorAMD64.cc b/dev/kernel/HALKit/AMD64/HalProcessorAMD64.cc new file mode 100644 index 00000000..b3da8352 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalProcessorAMD64.cc @@ -0,0 +1,101 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: HalCPU.cc + Purpose: Platform processor routines. + +------------------------------------------- */ + +#include <HALKit/AMD64/Paging.h> +#include <HALKit/AMD64/Processor.h> + +/** + * @file HalCPU.cc + * @brief Common CPU API. + */ + +namespace NeOS::HAL +{ + Void lrt_out8(UInt16 port, UInt8 value) + { + asm volatile("outb %%al, %1" + : + : "a"(value), "Nd"(port) + : "memory"); + } + + Void lrt_out16(UInt16 port, UInt16 value) + { + asm volatile("outw %%ax, %1" + : + : "a"(value), "Nd"(port) + : "memory"); + } + + Void lrt_out32(UInt16 port, UInt32 value) + { + asm volatile("outl %%eax, %1" + : + : "a"(value), "Nd"(port) + : "memory"); + } + + UInt8 lrt_in8(UInt16 port) + { + UInt8 value = 0UL; + asm volatile("inb %1, %%al" + : "=a"(value) + : "Nd"(port) + : "memory"); + + return value; + } + + UInt16 lrt_in16(UInt16 port) + { + UInt16 value = 0UL; + asm volatile("inw %1, %%ax" + : "=a"(value) + : "Nd"(port) + : "memory"); + + return value; + } + + UInt32 lrt_in32(UInt16 port) + { + UInt32 value = 0UL; + asm volatile("inl %1, %%eax" + : "=a"(value) + : "Nd"(port) + : "memory"); + + return value; + } + + Void rt_halt() + { + asm volatile("hlt"); + } + + Void rt_cli() + { + asm volatile("cli"); + } + + Void rt_sti() + { + asm volatile("sti"); + } + + Void rt_cld() + { + asm volatile("cld"); + } + + Void rt_std() + { + asm volatile("std"); + } +} // namespace NeOS::HAL diff --git a/dev/kernel/HALKit/AMD64/HalRoutineWait.s b/dev/kernel/HALKit/AMD64/HalRoutineWait.s new file mode 100644 index 00000000..89051ba4 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalRoutineWait.s @@ -0,0 +1,11 @@ +.globl rt_wait_400ns + +.section .text +rt_wait_400ns: + jmp .loop + pause + .loop: + jmp .loop2 + pause + .loop2: + ret diff --git a/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc b/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc new file mode 100644 index 00000000..bf4b9d91 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalSchedulerCorePrimitivesAMD64.cc @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/AMD64/Processor.h> +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Unimplemented function (crashes by default) + /// @param + /***********************************************************************************/ + + EXTERN_C Void __zka_pure_call(UserProcess* process) + { + if (process) + process->Crash(); + } + + /***********************************************************************************/ + /// @brief Validate user stack. + /// @param stack_ptr the frame pointer. + /***********************************************************************************/ + + EXTERN_C Bool hal_check_stack(HAL::StackFramePtr stack_ptr) + { + if (!stack_ptr) + return No; + + return stack_ptr->SP != 0 && stack_ptr->BP != 0; + } + + /// @brief Wakes up thread. + /// Wakes up thread from the hang state. + Void mp_wakeup_thread(HAL::StackFrame* stack) + { + NeOS::UserProcessHelper::StartScheduling(); + } + + /// @brief makes the thread sleep on a loop. + /// hooks and hangs thread to prevent code from executing. + Void mp_hang_thread(HAL::StackFrame* stack) + { + while (Yes) + { + /* Nothing to do, code is spinning */ + } + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/HalSystemCallInstall.cc b/dev/kernel/HALKit/AMD64/HalSystemCallInstall.cc new file mode 100644 index 00000000..e4e9daab --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalSystemCallInstall.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> diff --git a/dev/kernel/HALKit/AMD64/HalTimerAMD64.cc b/dev/kernel/HALKit/AMD64/HalTimerAMD64.cc new file mode 100644 index 00000000..53386d36 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalTimerAMD64.cc @@ -0,0 +1,86 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+ File: HalTimer.cc
+ Purpose: HAL timer
+
+ Revision History:
+
+ 07/07/24: Added file (amlel)
+
+------------------------------------------- */
+
+#include <modules/ACPI/ACPIFactoryInterface.h>
+#include <ArchKit/ArchKit.h>
+#include <KernelKit/Timer.h>
+
+// timer slot 0
+
+#define cHPETCounterRegValue (0x00)
+#define cHPETConfigRegValue (0x20)
+#define cHPETCompRegValue (0x24)
+#define cHPETInterruptRegValue (0x2C)
+
+///! BUGS: 0
+///! @file HalTimer.cc
+///! @brief Hardware Timer (HPET)
+
+namespace NeOS::Detail
+{
+ struct HPET_BLOCK : public NeOS::SDT
+ {
+ NeOS::UInt8 hardware_rev_id;
+ NeOS::UInt8 comparator_count : 5;
+ NeOS::UInt8 counter_size : 1;
+ NeOS::UInt8 reserved : 1;
+ NeOS::UInt8 legacy_replacement : 1;
+ NeOS::UInt16 pci_vendor_id;
+ ACPI_ADDRESS address;
+ NeOS::UInt8 hpet_number;
+ NeOS::UInt16 minimum_tick;
+ NeOS::UInt8 page_protection;
+ } PACKED;
+} // namespace NeOS::Detail
+
+using namespace NeOS;
+
+HardwareTimer::HardwareTimer(Int64 ms)
+ : fWaitFor(ms)
+{
+ auto power = PowerFactoryInterface(kHandoverHeader->f_HardwareTables.f_VendorPtr);
+
+ auto hpet = (Detail::HPET_BLOCK*)power.Find("HPET").Leak().Leak();
+ MUST_PASS(hpet);
+
+ fDigitalTimer = (IntPtr*)hpet->address.Address;
+}
+
+HardwareTimer::~HardwareTimer()
+{
+ fDigitalTimer = nullptr;
+ fWaitFor = 0;
+}
+
+BOOL HardwareTimer::Wait() noexcept
+{
+ if (fWaitFor < 1)
+ return NO;
+
+ // if not enabled yet.
+ if (!(*(fDigitalTimer + cHPETConfigRegValue) & (1 << 0)))
+ {
+ *(fDigitalTimer + cHPETConfigRegValue) |= (1 << 0); // enable it
+ *(fDigitalTimer + cHPETConfigRegValue) |= (1 << 3); // one shot conf
+ }
+
+ UInt64 ticks = fWaitFor / ((*(fDigitalTimer) >> 32) & __UINT32_MAX__);
+ UInt64 prev = *(fDigitalTimer + cHPETCounterRegValue);
+
+ prev += ticks;
+
+ while (*(fDigitalTimer + cHPETCounterRegValue) < (ticks))
+ ;
+
+ return YES;
+}
diff --git a/dev/kernel/HALKit/AMD64/HalUtils.asm b/dev/kernel/HALKit/AMD64/HalUtils.asm new file mode 100644 index 00000000..83453714 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/HalUtils.asm @@ -0,0 +1,26 @@ +;; /* +;; * ======================================================== +;; * +;; * NeKernel +;; * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. +;; * +;; * ======================================================== +;; */ + +[bits 64] + +[global rt_install_tib] + +section .text + +;; changed: rs, fs +;; expected: rcx, rdx + +rt_install_tib: + mov rcx, gs ;; TIB -> Thread Information Block + mov rdx, fs ;; PIB -> Process Information Block + ret + +;; //////////////////////////////////////////////////// ;; + +[extern kApicMadtAddressesCount] diff --git a/dev/kernel/HALKit/AMD64/Hypervisor.h b/dev/kernel/HALKit/AMD64/Hypervisor.h new file mode 100644 index 00000000..4c226eee --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Hypervisor.h @@ -0,0 +1,25 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + MAKE_STRING_ENUM(HYPERVISOR) + ENUM_STRING(Qemu, "TCGTCGTCGTCG"); + ENUM_STRING(KVM, " KVMKVMKVM "); + ENUM_STRING(VMWare, "VMwareVMware"); + ENUM_STRING(VirtualBox, "VBoxVBoxVBox"); + ENUM_STRING(Xen, "XenVMMXenVMM"); + ENUM_STRING(Microsoft, "Microsoft Hv"); + ENUM_STRING(Parallels, " prl hyperv "); + ENUM_STRING(ParallelsAlt, " lrpepyh vr "); + ENUM_STRING(Bhyve, "bhyve bhyve "); + ENUM_STRING(Qnx, " QNXQVMBSQG "); + END_STRING_ENUM() +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/MBCI/HalMBCI.cc b/dev/kernel/HALKit/AMD64/MBCI/HalMBCI.cc new file mode 100644 index 00000000..09632bc9 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/MBCI/HalMBCI.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/MBCI/MBCI.h> diff --git a/dev/kernel/HALKit/AMD64/PCI/DMA.cc b/dev/kernel/HALKit/AMD64/PCI/DMA.cc new file mode 100644 index 00000000..c756a572 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/PCI/DMA.cc @@ -0,0 +1,87 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/PCI/DMA.h> + +namespace NeOS +{ + DMAWrapper::operator bool() + { + return this->fAddress; + } + + bool DMAWrapper::operator!() + { + return !this->fAddress; + } + + Boolean DMAWrapper::Check(UIntPtr offset) const + { + if (!this->fAddress) + return false; + + if (offset == 0) + return false; + + kout << "[DMAWrapper::IsIn] Checking offset..\n"; + return reinterpret_cast<UIntPtr>(this->fAddress) >= offset; + } + + bool DMAWrapper::Write(const UIntPtr& bit, const UInt32& offset) + { + kout << "[DMAWrapper::Read] Checking this->fAddress..\n"; + + if (!this->fAddress) + return false; + + kout << "[DMAWrapper::Write] Writing at address..\n"; + + auto addr = + (volatile UIntPtr*)(reinterpret_cast<UIntPtr>(this->fAddress) + offset); + *addr = bit; + + return true; + } + + UIntPtr DMAWrapper::Read(const UInt32& offset) + { + kout << "[DMAWrapper::Read] Checking this->fAddress..\n"; + + if (!this->fAddress) + return 0; + + kout << "[DMAWrapper::Read] Reading this->fAddress..\n"; + + return *(volatile UIntPtr*)(reinterpret_cast<UIntPtr>(this->fAddress) + offset); + ; + } + + UIntPtr DMAWrapper::operator[](const UIntPtr& offset) + { + return this->Read(offset); + } + + OwnPtr<IOBuf<Char*>> DMAFactory::Construct(OwnPtr<DMAWrapper>& dma) + { + if (!dma) + return {}; + + OwnPtr<IOBuf<Char*>> dmaOwnPtr = + make_ptr<IOBuf<Char*>, char*>(reinterpret_cast<char*>(dma->fAddress)); + + if (!dmaOwnPtr) + return {}; + + kout << "Returning the new OwnPtr<IOBuf<Char*>>!\r"; + return dmaOwnPtr; + } + + DMAWrapper& DMAWrapper::operator=(voidPtr Ptr) + { + this->fAddress = Ptr; + return *this; + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/PCI/Database.cc b/dev/kernel/HALKit/AMD64/PCI/Database.cc new file mode 100644 index 00000000..c5aa1282 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/PCI/Database.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/PCI/Database.h> + +namespace NeOS +{ +} diff --git a/dev/kernel/HALKit/AMD64/PCI/Device.cc b/dev/kernel/HALKit/AMD64/PCI/Device.cc new file mode 100644 index 00000000..348e058a --- /dev/null +++ b/dev/kernel/HALKit/AMD64/PCI/Device.cc @@ -0,0 +1,171 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/PCI/Device.h> + +#define PCI_BAR_IO 0x01 +#define PCI_BAR_LOWMEM 0x02 +#define PCI_BAR_64 0x04 +#define PCI_BAR_PREFETCH 0x08 + +NeOS::UInt NE_PCIReadRaw(NeOS::UInt bar, NeOS::UShort bus, NeOS::UShort dev, NeOS::UShort fun) +{ + NeOS::UInt target = 0x80000000 | ((NeOS::UInt)bus << 16) | + ((NeOS::UInt)dev << 11) | ((NeOS::UInt)fun << 8) | + (bar & 0xFC); + + NeOS::HAL::rt_out32((NeOS::UShort)NeOS::PCI::PciConfigKind::ConfigAddress, + target); + + NeOS::HAL::rt_wait_400ns(); + + return NeOS::HAL::rt_in32((NeOS::UShort)NeOS::PCI::PciConfigKind::ConfigData); +} + +void NE_PCISetCfgTarget(NeOS::UInt bar, NeOS::UShort bus, NeOS::UShort dev, NeOS::UShort fun) +{ + NeOS::UInt target = 0x80000000 | ((NeOS::UInt)bus << 16) | + ((NeOS::UInt)dev << 11) | ((NeOS::UInt)fun << 8) | + (bar & 0xFC); + + NeOS::HAL::rt_out32((NeOS::UShort)NeOS::PCI::PciConfigKind::ConfigAddress, + target); + + NeOS::HAL::rt_wait_400ns(); +} + +namespace NeOS::PCI +{ + Device::Device(UShort bus, UShort device, UShort func, UInt32 bar) + : fBus(bus), fDevice(device), fFunction(func), fBar(bar) + { + } + + Device::~Device() = default; + + UInt Device::Read(UInt bar, Size sz) + { + // Ensure aligned access by masking to 4-byte boundary + NE_PCISetCfgTarget(bar & 0xFC, fBus, fDevice, fFunction); + + // Read 4 bytes and shift out the correct value + UInt data = HAL::rt_in32((UShort)PciConfigKind::ConfigData); + + if (sz == 4) + return data; + if (sz == 2) + return (data >> ((bar & 2) * 8)) & 0xFFFF; + if (sz == 1) + return (data >> ((bar & 3) * 8)) & 0xFF; + + return (UShort)PciConfigKind::Invalid; + } + + void Device::Write(UInt bar, UIntPtr data, Size sz) + { + NE_PCISetCfgTarget(bar & 0xFC, fBus, fDevice, fFunction); + + if (sz == 4) + HAL::rt_out32((UShort)PciConfigKind::ConfigData, (UInt)data); + else if (sz == 2) + { + UInt temp = HAL::rt_in32((UShort)PciConfigKind::ConfigData); + temp &= ~(0xFFFF << ((bar & 2) * 8)); + temp |= (data & 0xFFFF) << ((bar & 2) * 8); + HAL::rt_out32((UShort)PciConfigKind::ConfigData, temp); + } + else if (sz == 1) + { + UInt temp = HAL::rt_in32((UShort)PciConfigKind::ConfigData); + temp &= ~(0xFF << ((bar & 3) * 8)); + temp |= (data & 0xFF) << ((bar & 3) * 8); + HAL::rt_out32((UShort)PciConfigKind::ConfigData, temp); + } + } + + UShort Device::DeviceId() + { + return (UShort)(NE_PCIReadRaw(0x0, fBus, fDevice, fFunction) >> 16); + } + + UShort Device::VendorId() + { + return (UShort)(NE_PCIReadRaw(0x0, fBus, fDevice, fFunction) & 0xFFFF); + } + + UShort Device::InterfaceId() + { + return (UShort)(NE_PCIReadRaw(0x0, fBus, fDevice, fFunction) >> 16); + } + + UChar Device::Class() + { + return (UChar)(NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 24); + } + + UChar Device::Subclass() + { + return (UChar)(NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 16); + } + + UChar Device::ProgIf() + { + return (UChar)(NE_PCIReadRaw(0x08, fBus, fDevice, fFunction) >> 8); + } + + UChar Device::HeaderType() + { + return (UChar)(NE_PCIReadRaw(0xC, fBus, fDevice, fFunction) >> 16); + } + + void Device::EnableMmio(UInt32 bar_in) + { + UInt32 enable = Read(bar_in, sizeof(UInt32)); + enable |= (1 << 1); + + Write(bar_in, enable, sizeof(UInt32)); + } + + void Device::BecomeBusMaster(UInt32 bar_in) + { + UInt32 enable = Read(bar_in, sizeof(UInt32)); + enable |= (1 << 2); + + Write(bar_in, enable, sizeof(UInt32)); + } + + UIntPtr Device::Bar(UInt32 bar_in) + { + UInt32 bar = NE_PCIReadRaw(bar_in & ~0x03, fBus, fDevice, fFunction); + + if (bar & PCI_BAR_IO) + return static_cast<UIntPtr>(bar & ~0x03); + + if (bar & PCI_BAR_64) + { + UInt32 high = NE_PCIReadRaw((bar_in + 4) & ~0x03, fBus, fDevice, fFunction); + return (static_cast<UIntPtr>(high) << 32) | (bar & ~0x0F); + } + + return static_cast<UIntPtr>(bar & ~0x0F); + } + + UShort Device::Vendor() + { + UShort vendor = VendorId(); + + if (vendor != (UShort)PciConfigKind::Invalid) + fDevice = (UShort)Read(0x0, sizeof(UShort)); + + return fDevice; + } + + Device::operator bool() + { + return VendorId() != (UShort)PciConfigKind::Invalid; + } +} // namespace NeOS::PCI diff --git a/dev/kernel/HALKit/AMD64/PCI/Express.cc b/dev/kernel/HALKit/AMD64/PCI/Express.cc new file mode 100644 index 00000000..487cbd39 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/PCI/Express.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/PCI/Express.h> + +namespace NeOS +{ +} diff --git a/dev/kernel/HALKit/AMD64/PCI/IO.cc b/dev/kernel/HALKit/AMD64/PCI/IO.cc new file mode 100644 index 00000000..c20e1b0e --- /dev/null +++ b/dev/kernel/HALKit/AMD64/PCI/IO.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/PCI/IO.h> diff --git a/dev/kernel/HALKit/AMD64/PCI/Iterator.cc b/dev/kernel/HALKit/AMD64/PCI/Iterator.cc new file mode 100644 index 00000000..bf215fe2 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/PCI/Iterator.cc @@ -0,0 +1,39 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/PCI/Iterator.h> + +namespace NeOS::PCI +{ + Iterator::Iterator(const Types::PciDeviceKind& type) + { + // probe devices. + for (int bus = 0; bus < NE_BUS_COUNT; ++bus) + { + for (int device = 0; device < NE_DEVICE_COUNT; ++device) + { + for (int function = 0; function < NE_FUNCTION_COUNT; ++function) + { + Device dev(bus, device, function, 0x00); + + if (dev.Class() == type) + { + fDevices[bus] = dev; + } + } + } + } + } + + Iterator::~Iterator() + { + } + + Ref<PCI::Device> Iterator::operator[](const Size& at) + { + return fDevices[at]; + } +} // namespace NeOS::PCI diff --git a/dev/kernel/HALKit/AMD64/PCI/PCI.cc b/dev/kernel/HALKit/AMD64/PCI/PCI.cc new file mode 100644 index 00000000..01f2c23b --- /dev/null +++ b/dev/kernel/HALKit/AMD64/PCI/PCI.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/PCI/PCI.h> diff --git a/dev/kernel/HALKit/AMD64/Paging.h b/dev/kernel/HALKit/AMD64/Paging.h new file mode 100644 index 00000000..4e2ac1b1 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Paging.h @@ -0,0 +1,99 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +/** --------------------------------------------------- + + * THIS FILE CONTAINS CODE FOR X86_64 PAGING. + +------------------------------------------------------- */ + +#include <NewKit/Defines.h> + +#ifndef kPageMax +#define kPageMax (0x200) +#endif //! kPageMax + +#ifndef kPageAlign +#define kPageAlign (0x08) +#endif //! kPageAlign + +#ifndef kPageSize +#define kPageSize (0x1000) +#endif // !kPageSize + +#ifndef kAlign +#define kAlign __BIGGEST_ALIGNMENT__ +#endif // !kAlign + +EXTERN_C void hal_flush_tlb(); +EXTERN_C void hal_invl_tlb(NeOS::VoidPtr addr); +EXTERN_C void hal_write_cr3(NeOS::VoidPtr cr3); +EXTERN_C void hal_write_cr0(NeOS::VoidPtr bit); + +EXTERN_C NeOS::VoidPtr hal_read_cr0(); // @brief CPU control register. +EXTERN_C NeOS::VoidPtr hal_read_cr2(); // @brief Fault address. +EXTERN_C NeOS::VoidPtr hal_read_cr3(); // @brief Page table. + +namespace NeOS::HAL +{ + /// @brief Final page entry (Not PML, PDPT) + struct PACKED NE_PTE final + { + UInt64 Present : 1; + UInt64 Wr : 1; + UInt64 User : 1; + UInt64 Wt : 1; + UInt64 Cache : 1; + UInt64 Accessed : 1; + UInt64 Dirty : 1; + UInt64 MemoryType : 1; + UInt64 Global : 1; + UInt64 Resvered1 : 3; + UInt64 PhysicalAddress : 36; + UInt64 Reserved2 : 10; + UInt64 ProtectionKey : 5; + UInt64 ExecDisable : 1; + }; + + namespace Detail + { + enum class ControlRegisterBits + { + ProtectedModeEnable = 0, + MonitorCoProcessor = 1, + Emulation = 2, + TaskSwitched = 3, + ExtensionType = 4, + NumericError = 5, + WriteProtect = 16, + AlignementMask = 18, + NotWriteThrough = 29, + CacheDisable = 30, + PageEnable = 31, + }; + + inline UInt8 control_register_cast(ControlRegisterBits reg) + { + return static_cast<UInt8>(reg); + } + } // namespace Detail + + struct NE_PDE final + { + NE_PTE* ALIGN(kPageAlign) fEntries[kPageMax]; + }; + + auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page) -> VoidPtr; + auto mm_free_bitmap(VoidPtr page_ptr) -> Bool; +} // namespace NeOS::HAL + +namespace NeOS +{ + typedef HAL::NE_PTE PTE; + typedef HAL::NE_PDE PDE; +} // namespace NeOS diff --git a/dev/kernel/HALKit/AMD64/Processor.h b/dev/kernel/HALKit/AMD64/Processor.h new file mode 100644 index 00000000..d223c320 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Processor.h @@ -0,0 +1,326 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: Prcoessor.h + Purpose: AMD64 processor abstraction. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/Utils.h> +#include <FirmwareKit/Handover.h> +#include <HALKit/AMD64/Paging.h> + +#define kPITControlPort (0x43) +#define kPITChannel0Port (0x40) +#define kPITFrequency (1193180) + +#define kPICCommand (0x20) +#define kPICData (0x21) +#define kPIC2Command (0xA0) +#define kPIC2Data (0xA1) + +EXTERN_C +{ +#include <cpuid.h> +} + +#include <HALKit/AMD64/CPUID.h> + +/// @brief Maximum entries of the interrupt descriptor table. +#define kKernelIdtSize (0x100) + +/// @brief interrupt for system call. +#define kKernelInterruptId (0x32) + +#define IsActiveLow(FLG) (FLG & 2) +#define IsLevelTriggered(FLG) (FLG & 8) + +#define kInterruptGate (0x8E) +#define kTrapGate (0xEF) +#define kTaskGate (0b10001100) +#define kIDTSelector (0x08) + +namespace NeOS +{ + namespace Detail::AMD64 + { + struct PACKED InterruptDescriptorAMD64 final + { + UInt16 OffsetLow; // offset bits 0..15 + UInt16 Selector; // a code segment selector in GDT or LDT + UInt8 Ist; + UInt8 TypeAttributes; + UInt16 OffsetMid; + UInt32 OffsetHigh; + UInt32 Zero; // reserved + }; + } // namespace Detail::AMD64 +} // namespace NeOS + +namespace NeOS::HAL +{ + /// @brief Memory Manager mapping flags. + enum + { + kMMFlagsInvalid = 0 << 0, + kMMFlagsPresent = 1 << 0, + kMMFlagsWr = 1 << 1, + kMMFlagsUser = 1 << 2, + kMMFlagsNX = 1 << 3, + kMMFlagsCount = 4, + }; + + struct PACKED Register64 final + { + UShort Limit; + UIntPtr Base; + }; + + struct PACKED RegisterGDT final + { + UShort Limit; + UIntPtr Base; + }; + + using RawRegister = UInt64; + using Reg = RawRegister; + using InterruptId = UInt16; /* For each element in the IVT */ + + /// @brief Stack frame (as retrieved from assembly.) + struct PACKED StackFrame final + { + RawRegister R8{0}; + RawRegister R9{0}; + RawRegister R10{0}; + RawRegister FS{0}; + RawRegister R12{0}; + RawRegister R13{0}; + RawRegister R14{0}; + RawRegister R15{0}; + RawRegister GS{0}; + RawRegister SP{0}; + RawRegister BP{0}; + }; + + typedef StackFrame* StackFramePtr; + + class InterruptDescriptor final + { + public: + UShort Offset; + UShort Selector; + UChar Ist; + UChar Atrributes; + + UShort SecondOffset; + UInt ThirdOffset; + UInt Zero; + + operator bool() + { + return Offset != 0xFFFF; + } + }; + + using InterruptDescriptorArray = Array<InterruptDescriptor, 256>; + + class SegmentDescriptor final + { + public: + UInt16 Base; + UInt8 BaseMiddle; + UInt8 BaseHigh; + + UShort Limit; + UChar Gran; + UChar AccessByte; + }; + + /*** + * @brief Segment Boolean operations + */ + class SegmentDescriptorComparator final + { + public: + Bool IsValid(SegmentDescriptor& seg) + { + return seg.Base > seg.Limit; + } + + Bool Equals(SegmentDescriptor& seg, SegmentDescriptor& segRight) + { + return seg.Base == segRight.Base && seg.Limit == segRight.Limit; + } + }; + + using SegmentArray = Array<SegmentDescriptor, 6>; + + class GDTLoader final + { + public: + static Void Load(RegisterGDT& gdt); + static Void Load(Ref<RegisterGDT>& gdt); + }; + + class IDTLoader final + { + public: + static Void Load(Register64& idt); + static Void Load(Ref<Register64>& idt); + }; + + /***********************************************************************************/ + /// @brief Is the current config SMP aware? + /// @return True if YES, False if not. + /***********************************************************************************/ + + Bool mp_is_smp(Void) noexcept; + + /***********************************************************************************/ + /// @brief Fetch and enable SMP scheduler. + /// @param vendor_ptr SMP containing structure. + /***********************************************************************************/ + Void mp_get_cores(VoidPtr vendor_ptr) noexcept; + + /***********************************************************************************/ + /// @brief Do a cpuid to check if MSR exists on CPU. + /// @retval true it does exists. + /// @retval false it doesn't. + /***********************************************************************************/ + inline Bool hal_has_msr() noexcept + { + static UInt32 eax, unused, edx; // eax, edx + + __get_cpuid(1, &eax, &unused, &unused, &edx); + + // edx returns the flag for MSR (which is 1 shifted to 5.) + return edx & (1 << 5); + } + + UIntPtr hal_get_phys_address(VoidPtr virtual_address); + + /***********************************************************************************/ + /// @brief Get Model specific register inside core. + /// @param msr MSR + /// @param lo low byte + /// @param hi high byte + /***********************************************************************************/ + inline UInt32 hal_get_msr(UInt32 msr, UInt32* lo, UInt32* hi) noexcept + { + if (!lo || !hi) + return 0; + + asm volatile("rdmsr" + : "=a"(*lo), "=d"(*hi) + : "c"(msr)); + + return *lo + *hi; + } + + /// @brief Set Model-specific register. + /// @param msr MSR + /// @param lo low byte + /// @param hi high byte + inline Void hal_set_msr(UInt32 msr, UInt32 lo, UInt32 hi) noexcept + { + asm volatile("wrmsr" + : + : "a"(lo), "d"(hi), "c"(msr)); + } + + /// @brief Processor specific namespace. + namespace Detail + { + /* @brief TSS struct. */ + struct NE_TSS final + { + UInt32 fReserved1; + UInt64 fRsp0; + UInt64 fRsp1; + UInt64 fRsp2; + UInt64 fReserved2; + UInt64 fIst1; + UInt64 fIst2; + UInt64 fIst3; + UInt64 fIst4; + UInt64 fIst5; + UInt64 fIst6; + UInt64 fIst7; + UInt64 fReserved3; + UInt16 fReserved4; + UInt16 fIopb; + }; + + /** + @brief Global descriptor table entry, either null, code or data. + */ + + struct PACKED NE_GDT_ENTRY final + { + UInt16 fLimitLow; + UInt16 fBaseLow; + UInt8 fBaseMid; + UInt8 fAccessByte; + UInt8 fFlags; + UInt8 fBaseHigh; + }; + } // namespace Detail + + class APICController final + { + public: + explicit APICController(VoidPtr base); + ~APICController() = default; + + NE_COPY_DEFAULT(APICController); + + public: + UInt32 Read(UInt32 reg) noexcept; + Void Write(UInt32 reg, UInt32 value) noexcept; + + private: + VoidPtr fApic{nullptr}; + }; + + /// @brief Set a PTE from pd_base. + /// @param virt_addr a valid virtual address. + /// @param phys_addr point to physical address. + /// @param flags the flags to put on the page. + /// @return Status code of page manip. + EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags); + + EXTERN_C UInt8 rt_in8(UInt16 port); + EXTERN_C UInt16 rt_in16(UInt16 port); + EXTERN_C UInt32 rt_in32(UInt16 port); + + EXTERN_C Void rt_out16(UShort port, UShort byte); + EXTERN_C Void rt_out8(UShort port, UChar byte); + EXTERN_C Void rt_out32(UShort port, UInt byte); + + EXTERN_C Void rt_wait_400ns(); + EXTERN_C Void rt_halt(); + EXTERN_C Void rt_cli(); + EXTERN_C Void rt_sti(); + EXTERN_C Void rt_cld(); + EXTERN_C Void rt_std(); +} // namespace NeOS::HAL + +EXTERN_C NeOS::Void idt_handle_generic(NeOS::UIntPtr rsp); +EXTERN_C NeOS::Void idt_handle_gpf(NeOS::UIntPtr rsp); +EXTERN_C NeOS::Void idt_handle_math(NeOS::UIntPtr rsp); +EXTERN_C NeOS::Void idt_handle_pf(NeOS::UIntPtr rsp); + +EXTERN_C ATTRIBUTE(naked) NeOS::Void hal_load_idt(NeOS::HAL::Register64 ptr); +EXTERN_C ATTRIBUTE(naked) NeOS::Void hal_load_gdt(NeOS::HAL::RegisterGDT ptr); + +inline NeOS::VoidPtr kKernelBitMpStart = nullptr; +inline NeOS::UIntPtr kKernelBitMpSize = 0UL; diff --git a/dev/kernel/HALKit/AMD64/ReadMe.md b/dev/kernel/HALKit/AMD64/ReadMe.md new file mode 100644 index 00000000..02c8c86f --- /dev/null +++ b/dev/kernel/HALKit/AMD64/ReadMe.md @@ -0,0 +1,8 @@ +# AMD64 Hardware Abstraction Layer + +## Brief + +- Supported CPU: AMD64 BASED CPUs. +- Supported Firmware: EDK 2. + +###### Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. All rights reserved. diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc new file mode 100644 index 00000000..002266de --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc @@ -0,0 +1,424 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss Corporation, all rights reserved. + +------------------------------------------- */ + +/** + * @file AHCI.cc + * @author Amlal El Mahrouss (amlalelmahrouss@icloud.com) + * @brief AHCI driver. + * @version 0.1 + * @date 2024-02-02 + * + * @copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + * + */ + +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/DriveMgr.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/LPC.h> + +#include <FirmwareKit/EPM.h> + +#include <modules/ATA/ATA.h> +#include <modules/AHCI/AHCI.h> +#include <KernelKit/PCI/Iterator.h> +#include <NewKit/Utils.h> +#include <KernelKit/LockDelegate.h> + +#include <StorageKit/AHCI.h> + +#define kHBAErrTaskFile (1 << 30) +#define kHBAPxCmdST (0x0001) +#define kHBAPxCmdFre (0x0010) +#define kHBAPxCmdFR (0x4000) +#define kHBAPxCmdCR (0x8000) + +#define kSATALBAMode (1 << 6) + +#define kSATASRBsy (0x80) +#define kSATASRDrq (0x08) + +#define kHBABohcBiosOwned (1 << 0) +#define kHBABohcOSOwned (1 << 1) + +#define kSATAPortCnt (0x20) + +#define kSATASig (0x00000101) +#define kSATAPISig (0xEB140101) + +#define kSATAProgIfAHCI (0x01) +#define kSATASubClass (0x06) +#define kSATABar5 (0x24) + +using namespace NeOS; + +STATIC PCI::Device kSATADev; +STATIC HbaMem* kSATAHba; +STATIC Lba kSATASectorCount = 0UL; +STATIC UInt16 kSATAIndex = 0U; +STATIC Char kCurrentDiskModel[50] = {"UNKNOWN AHCI DRIVE"}; +STATIC UInt16 kSATAPortsImplemented = 0U; + +template <BOOL Write, BOOL CommandOrCTRL, BOOL Identify> +STATIC Void drv_std_input_output(UInt64 lba, UInt8* buffer, SizeT sector_sz, SizeT size_buffer) noexcept; + +STATIC Int32 drv_find_cmd_slot(HbaPort* port) noexcept; + +STATIC Void drv_compute_disk_ahci() noexcept; + +STATIC Void drv_compute_disk_ahci() noexcept +{ + kSATASectorCount = 0UL; + + const UInt16 kSzIdent = kib_cast(1); + + UInt8 identify_data[kSzIdent] = {0}; + + rt_set_memory(identify_data, 0, kSzIdent); + + drv_std_input_output<NO, YES, YES>(0, identify_data, kAHCISectorSize, kSzIdent); + + kSATASectorCount = (identify_data[61] << 16) | identify_data[60]; + + kout << "Disk Model: " << kCurrentDiskModel << kendl; + kout << "Disk Size: " << number(drv_get_size()) << kendl; + kout << "Disk Sector Count: " << number(kSATASectorCount) << kendl; +} + +STATIC Int32 drv_find_cmd_slot(HbaPort* port) noexcept +{ + UInt32 slots = (port->Sact | port->Ci); + + for (Int32 i = 0; i < kSATAPortCnt; ++i) + { + if ((slots & 1) == 0) + return i; + + slots >>= 1; + } + + return ~0; +} + +template <BOOL Write, BOOL CommandOrCTRL, BOOL Identify> +STATIC Void drv_std_input_output(UInt64 lba, UInt8* buffer, SizeT sector_sz, SizeT size_buffer) noexcept +{ + UIntPtr slot = 0UL; + + slot = drv_find_cmd_slot(&kSATAHba->Ports[kSATAIndex]); + + if (slot == ~0) + return; + + volatile HbaCmdHeader* command_header = ((HbaCmdHeader*)(((UInt64)kSATAHba->Ports[kSATAIndex].Clb))); + + command_header += slot; + + MUST_PASS(command_header); + + command_header->Cfl = sizeof(FisRegH2D) / sizeof(UInt32); + command_header->Write = Write; + command_header->Prdtl = (UInt16)((size_buffer - 1) >> 4) + 1; + + HbaCmdTbl* command_table = (HbaCmdTbl*)((VoidPtr)((UInt64)command_header->Ctba)); + + rt_set_memory(command_table, 0, sizeof(HbaCmdTbl) + (command_header->Prdtl - 1) * sizeof(HbaPrdtEntry)); + + MUST_PASS(command_table); + + UIntPtr buffer_phys = HAL::hal_get_phys_address(buffer); + + UInt16 prd_i = 0; + + for (; prd_i < (command_header->Prdtl - 1); prd_i++) + { + command_table->Prdt[prd_i].Dbc = ((size_buffer / command_header->Prdtl - 1) - 1); + command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys + (prd_i * command_table->Prdt[prd_i].Dbc)); + command_table->Prdt[prd_i].Dbau = (((UInt64)(buffer_phys) >> 32) + (prd_i * command_table->Prdt[prd_i].Dbc)); + command_table->Prdt[prd_i].Ie = YES; + } + + command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys + (prd_i * command_table->Prdt[prd_i].Dbc)); + command_table->Prdt[prd_i].Dbau = (((UInt64)(buffer_phys) >> 32) + (prd_i * command_table->Prdt[prd_i].Dbc)); + command_table->Prdt[prd_i].Dbc = ((size_buffer / command_header->Prdtl - 1) - 1); + command_table->Prdt[prd_i].Ie = YES; + + FisRegH2D* h2d_fis = (FisRegH2D*)(&command_table->Cfis); + + h2d_fis->FisType = kFISTypeRegH2D; + h2d_fis->CmdOrCtrl = CommandOrCTRL; + h2d_fis->Command = Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx; + + if (Identify) + h2d_fis->Command = kAHCICmdIdentify; + + h2d_fis->Lba0 = (lba)&0xFF; + h2d_fis->Lba1 = (lba >> 8) & 0xFF; + h2d_fis->Lba2 = (lba >> 16) & 0xFF; + + h2d_fis->Device = Identify ? 0U : kSATALBAMode; + + h2d_fis->Lba3 = (lba >> 24) & 0xFF; + h2d_fis->Lba4 = (lba >> 32) & 0xFF; + h2d_fis->Lba5 = (lba >> 40) & 0xFF; + + h2d_fis->CountLow = (size_buffer)&0xFF; + h2d_fis->CountHigh = (size_buffer >> 8) & 0xFF; + + while (kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq)) + { + ; + } + + kSATAHba->Ports[kSATAIndex].Ci = (1 << slot); + + while (YES) + { + if (!(kSATAHba->Ports[kSATAIndex].Ci & (1 << slot))) + break; + + if (kSATAHba->Is & kHBAErrTaskFile) + { + err_global_get() = kErrorDiskIsCorrupted; + return; + } + } + + if (kSATAHba->Is & kHBAErrTaskFile) + { + err_global_get() = kErrorDiskIsCorrupted; + return; + } +} + +/*** + @brief Gets the number of sectors inside the drive. + @return Sector size in bytes. + */ +SizeT drv_get_sector_count_ahci() +{ + return kSATASectorCount; +} + +/// @brief Get the drive size. +/// @return Disk size in bytes. +SizeT drv_get_size_ahci() +{ + return drv_get_sector_count() * kAHCISectorSize; +} + +/// @brief Enable Host and probe using the IDENTIFY command. +STATIC Void ahci_enable_and_probe() +{ + if (kSATAHba->Bohc & kHBABohcBiosOwned) + { + kSATAHba->Bohc |= kHBABohcOSOwned; + + while (kSATAHba->Bohc & kHBABohcBiosOwned) + { + ; + } + } + + // Poll until ready. + while (kSATAHba->Ports[kSATAIndex].Cmd & kHBAPxCmdCR) + { + ; + } + + kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdFre; + kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdST; + + drv_compute_disk_ahci(); +} + +/// @brief Initializes an AHCI disk. +/// @param pi the amount of ports that have been detected. +/// @param atapi reference value, tells whether we should detect ATAPI instead of SATA. +/// @return if the disk was successfully initialized or not. +STATIC Bool drv_std_init_ahci(UInt16& pi, BOOL& atapi) +{ + PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController); + + for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) + { + kSATADev = iterator[device_index].Leak(); // Leak device. + + if (kSATADev.Subclass() == kSATASubClass && + kSATADev.ProgIf() == kSATAProgIfAHCI) + { + HbaMem* mem_ahci = (HbaMem*)kSATADev.Bar(kSATABar5); + + kSATADev.EnableMmio((UIntPtr)mem_ahci); + kSATADev.BecomeBusMaster((UIntPtr)mem_ahci); + + UInt32 ports_implemented = mem_ahci->Pi; + UInt16 ahci_index = 0; + + pi = ports_implemented; + + const UInt16 kMaxPortsImplemented = kSATAPortCnt; + const UInt32 kSATASignature = kSATASig; + const UInt32 kSATAPISignature = kSATAPISig; + const UInt8 kSATAPresent = 0x03; + const UInt8 kSATAIPMActive = 0x01; + + kSATAHba = mem_ahci; + + while (ports_implemented) + { + UInt8 ipm = (mem_ahci->Ports[ahci_index].Ssts >> 8) & 0x0F; + UInt8 det = mem_ahci->Ports[ahci_index].Ssts & 0x0F; + + if (det != kSATAPresent || ipm != kSATAIPMActive) + continue; + + if (mem_ahci->Ports[ahci_index].Sig == kSATASignature) + { + kout << "Detect: /dev/sat" << number(ahci_index) << kendl; + + kSATAIndex = ahci_index; + kSATAHba = mem_ahci; + + ahci_enable_and_probe(); + + break; + } + else if (atapi && kSATAPISignature == mem_ahci->Ports[ahci_index].Sig) + { + kout << "Detect: /dev/atp" << number(ahci_index) << kendl; + + kSATAIndex = ahci_index; + kSATAHba = mem_ahci; + + ahci_enable_and_probe(); + + break; + } + + ports_implemented >>= 1; + ++ahci_index; + } + + return YES; + } + } + + return NO; +} + +Bool drv_std_detected_ahci() +{ + return kSATADev.DeviceId() != (UShort)PCI::PciConfigKind::Invalid && kSATADev.Bar(kSATABar5) != 0; +} + +namespace NeOS +{ + UInt16 sk_init_ahci_device(BOOL atapi) + { + UInt16 pi = 0; + return drv_std_init_ahci(pi, atapi); + + kSATAPortsImplemented = pi; + + return pi; + } + + namespace Detail + { + /// @brief Read AHCI device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_read_ahci(IDeviceObject<MountpointInterface*>* self, MountpointInterface* mnt) + { + AHCIDeviceInterface* dev = (AHCIDeviceInterface*)self; + + if (!dev) + return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) + return; + + drv_std_input_output<NO, YES, NO>(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); + } + + /// @brief Write AHCI device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_write_ahci(IDeviceObject<MountpointInterface*>* self, MountpointInterface* mnt) + { + AHCIDeviceInterface* dev = (AHCIDeviceInterface*)self; + + if (!dev) + return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) + return; + + drv_std_input_output<YES, YES, NO>(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); + } + } // namespace Detail + + ErrorOr<AHCIDeviceInterface> sk_acquire_ahci_device(Int32 drv_index) + { + if (!drv_std_detected_ahci()) + return ErrorOr<AHCIDeviceInterface>(kErrorDisk); + + AHCIDeviceInterface device(Detail::sk_io_read_ahci, + Detail::sk_io_write_ahci, + nullptr); + + device.SetPortsImplemented(kSATAPortsImplemented); + device.SetIndex(drv_index); + + return ErrorOr<AHCIDeviceInterface>(device); + } +} // namespace NeOS + +#ifdef __AHCI__ + +Void drv_std_write(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) +{ + drv_std_input_output<YES, YES, NO>(lba, (UInt8*)buffer, sector_sz, size_buffer); +} + +Void drv_std_read(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) +{ + drv_std_input_output<NO, YES, NO>(lba, (UInt8*)buffer, sector_sz, size_buffer); +} + +Bool drv_std_init(UInt16& pi) +{ + BOOL atapi = NO; + return drv_std_init_ahci(pi, atapi); +} + +Bool drv_std_detected(Void) +{ + return drv_std_detected_ahci(); +} + +/*** + @brief Gets the number of sectors inside the drive. + @return Sector size in bytes. + */ +SizeT drv_get_sector_count() +{ + return drv_get_sector_count_ahci(); +} + +/// @brief Get the drive size. +/// @return Disk size in bytes. +SizeT drv_get_size() +{ + return drv_get_size_ahci(); +} + +#endif // ifdef __AHCI__ diff --git a/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc new file mode 100644 index 00000000..e025d24d --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc @@ -0,0 +1,253 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/** + * @file ATA-PIO.cc + * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com) + * @brief ATA driver (PIO mode). + * @version 0.1 + * @date 2024-02-02 + * + * @copyright Copyright (c) Amlal EL Mahrouss + * + */ + +#include <modules/ATA/ATA.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/PCI/Iterator.h> + +#if defined(__ATA_DMA__) + +#define kATADataLen (256) + +using namespace NeOS; +using namespace NeOS::HAL; + +/// BUGS: 0 + +STATIC Boolean kATADetected = false; +STATIC Int32 kATADeviceType = kATADeviceCount; +STATIC Char kATAData[kATADataLen] = {0}; +STATIC NeOS::PCI::Device kATADevice; +STATIC Char kCurrentDiskModel[50] = {"UNKNOWN DMA DRIVE"}; + +Boolean drv_std_wait_io(UInt16 IO) +{ + for (int i = 0; i < 400; i++) + rt_in8(IO + ATA_REG_STATUS); + +ATAWaitForIO_Retry: + auto status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if ((status_rdy & ATA_SR_BSY)) + goto ATAWaitForIO_Retry; + +ATAWaitForIO_Retry2: + status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (status_rdy & ATA_SR_ERR) + return false; + + if (!(status_rdy & ATA_SR_DRDY)) + goto ATAWaitForIO_Retry2; + + return true; +} + +Void drv_std_select(UInt16 Bus) +{ + if (Bus == ATA_PRIMARY_IO) + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); + else + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); +} + +Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) +{ + PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController); + + for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) + { + kATADevice = iterator[device_index].Leak(); // And then leak the reference. + + // if SATA and then interface is AHCI... + if (kATADevice.Subclass() == 0x01) + { + UInt16 IO = Bus; + + drv_std_select(IO); + + // Bus init, NEIN bit. + rt_out8(IO + ATA_REG_NEIN, 1); + + // identify until it's good. + ATAInit_Retry: + auto status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (status_rdy & ATA_SR_ERR) + { + return false; + } + + if ((status_rdy & ATA_SR_BSY)) + goto ATAInit_Retry; + + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + + /// fetch serial info + /// model, speed, number of sectors... + + drv_std_wait_io(IO); + + for (SizeT i = 0ul; i < kATADataLen; ++i) + { + drv_std_wait_io(IO); + kATAData[i] = NeOS::HAL::rt_in16(IO + ATA_REG_DATA); + drv_std_wait_io(IO); + } + + for (SizeT i = 0; i < 40; i += 2) + { + kCurrentDiskModel[i * 2] = kATAData[27 + i * 2] >> 8; + kCurrentDiskModel[i * 2 + 1] = kATAData[27 + i * 2] & 0xFF; + } + + kCurrentDiskModel[40] = '\0'; + + kout << "Drive Model: " << kCurrentDiskModel << kendl; + + OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; + + return YES; + } + } + + ke_panic(RUNTIME_CHECK_BOOTSTRAP, "Invalid ATA DMA driver, not detected"); + + return NO; +} + +namespace Detail +{ + using namespace NeOS; + + struct PRDEntry + { + UInt32 mAddress; + UInt16 mByteCount; + UInt16 mFlags; + }; +} // namespace Detail + +static UIntPtr kReadAddr = mib_cast(2); +static UIntPtr kWriteAddr = mib_cast(4); + +Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + if (Size > kib_cast(64)) + ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers."); + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + rt_copy_memory((VoidPtr)Buf, (VoidPtr)kReadAddr, Size); + + drv_std_select(IO); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz - 1) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba)&0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + Detail::PRDEntry* prd = (Detail::PRDEntry*)(kATADevice.Bar(0x20) + 4); // The PRDEntry is not correct. + + prd->mAddress = (UInt32)(UIntPtr)kReadAddr; + prd->mByteCount = Size - 1; + prd->mFlags = 0x8000; // indicate the end of prd. + + rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32)(UIntPtr)prd); + + rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_READ_DMA); + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x09); // Start DMA engine + + while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01) + ; + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine + + rt_copy_memory((VoidPtr)kReadAddr, (VoidPtr)Buf, Size); + + delete prd; + prd = nullptr; +} + +Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + if (Size > kib_cast(64)) + ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers."); + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + rt_copy_memory((VoidPtr)Buf, (VoidPtr)kWriteAddr, Size); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + (SectorSz - 1)) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba)&0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + Detail::PRDEntry* prd = (Detail::PRDEntry*)(kATADevice.Bar(0x20) + 4); + prd->mAddress = (UInt32)(UIntPtr)kWriteAddr; + prd->mByteCount = Size - 1; + prd->mFlags = 0x8000; + + rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32)(UIntPtr)prd); + rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_WRITE_DMA); + + rt_out8(IO + 0x00, 0x09); // Start DMA engine + + while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01) + ; + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine + + delete prd; + prd = nullptr; +} + +/// @brief is ATA detected? +Boolean drv_std_detected(Void) +{ + return kATADetected; +} + +/*** + @brief Getter, gets the number of sectors inside the drive. +*/ +NeOS::SizeT drv_get_sector_count() +{ + return (kATAData[61] << 16) | kATAData[60]; +} + +/// @brief Get the drive size. +NeOS::SizeT drv_get_size() +{ + return (drv_get_sector_count()) * kATASectorSize; +} + +#endif /* ifdef __ATA_DMA__ */ diff --git a/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc new file mode 100644 index 00000000..cb629478 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc @@ -0,0 +1,191 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/** + * @file PIO.cc + * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com) + * @brief ATA driver (PIO mode). + * @version 0.1 + * @date 2024-02-02 + * + * @copyright Copyright (c) Amlal EL Mahrouss + * + */ + +#include <modules/ATA/ATA.h> +#include <ArchKit/ArchKit.h> + +#ifdef __ATA_PIO__ + +using namespace NeOS; +using namespace NeOS::HAL; + +/// BUGS: 0 + +#define kATADataLen 512 + +STATIC Boolean kATADetected = false; +STATIC Int32 kATADeviceType = kATADeviceCount; +STATIC Char kATAData[kATADataLen] = {0}; +STATIC Char kCurrentDiskModel[50] = {"UNKNOWN PIO DRIVE"}; + +Boolean drv_std_wait_io(UInt16 IO) +{ + for (int i = 0; i < 400; i++) + rt_in8(IO + ATA_REG_STATUS); + +ATAWaitForIO_Retry: + auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if ((stat_rdy & ATA_SR_BSY)) + goto ATAWaitForIO_Retry; + +ATAWaitForIO_Retry2: + stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (stat_rdy & ATA_SR_ERR) + return false; + + if (!(stat_rdy & ATA_SR_DRDY)) + goto ATAWaitForIO_Retry2; + + return true; +} + +Void drv_std_select(UInt16 Bus) +{ + if (Bus == ATA_PRIMARY_IO) + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); + else + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); +} + +Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) +{ + UInt16 IO = Bus; + + drv_std_select(IO); + + // Bus init, NEIN bit. + rt_out8(IO + ATA_REG_NEIN, 1); + + // identify until it's good. +ATAInit_Retry: + auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (stat_rdy & ATA_SR_ERR) + { + return false; + } + + if ((stat_rdy & ATA_SR_BSY)) + goto ATAInit_Retry; + + OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; + + rt_out8(OutBus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + + drv_std_wait_io(IO); + + /// fetch serial info + /// model, speed, number of sectors... + + for (SizeT i = 0ul; i < kATADataLen; ++i) + { + kATAData[i] = HAL::rt_in16(OutBus + ATA_REG_DATA); + } + + for (Int32 i = 0; i < 20; i++) + { + kCurrentDiskModel[i * 2] = kATAData[27 + i] >> 8; + kCurrentDiskModel[i * 2 + 1] = kATAData[27 + i + 1] & 0xFF; + } + + kCurrentDiskModel[40] = '\0'; + + kout << "Detect: /dev/ata0" << kendl; + + kout << "Drive Model: " << kCurrentDiskModel << kendl; + + return true; +} + +Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + drv_std_wait_io(IO); + drv_std_select(IO); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba)&0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); + + for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff) + { + drv_std_wait_io(IO); + Buf[IndexOff] = HAL::rt_in16(IO + ATA_REG_DATA); + } +} + +Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + drv_std_wait_io(IO); + drv_std_select(IO); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + (SectorSz)) / SectorSz)); + + rt_out8(IO + ATA_REG_LBA0, (Lba)&0xFF); + rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); + rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); + rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); + + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); + + for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff) + { + drv_std_wait_io(IO); + rt_out16(IO + ATA_REG_DATA, Buf[IndexOff]); + } +} + +/// @brief is ATA detected? +Boolean drv_std_detected(Void) +{ + return kATADetected; +} + +/*** + @brief Getter, gets the number of sectors inside the drive. + */ +SizeT drv_get_sector_count() +{ + return (kATAData[61] << 16) | kATAData[60]; +} + +/// @brief Get the drive size. +SizeT drv_get_size() +{ + return (drv_get_sector_count()) * kATASectorSize; +} + +#endif /* ifdef __ATA_PIO__ */
\ No newline at end of file diff --git a/dev/kernel/HALKit/AMD64/make_ap_blob.sh b/dev/kernel/HALKit/AMD64/make_ap_blob.sh new file mode 100755 index 00000000..3f079187 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/make_ap_blob.sh @@ -0,0 +1,3 @@ +# !/bin/sh + +nasm -f bin HalApplicationProcessorStartup.asm -o HalApplicationProcessorStartup.bin
\ No newline at end of file diff --git a/dev/kernel/HALKit/ARM64/APM/APM+IO.cc b/dev/kernel/HALKit/ARM64/APM/APM+IO.cc new file mode 100644 index 00000000..752f29f9 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/APM/APM+IO.cc @@ -0,0 +1,37 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/APM/APM.h> +#include <KernelKit/LPC.h> + +using namespace NeOS; + +/// @brief Send APM command to it's space. +/// @param base_dma the IO base port. +/// @param cmd the command. +/// @return status code. +EXTERN_C Int32 apm_send_io_command(UInt16 cmd, APMPowerCmd value) +{ + switch (cmd) + { + case kAPMPowerCommandReboot: { + asm volatile( + "ldr x0, =0x84000004\n" + "svc #0\n"); + + return kErrorSuccess; + } + case kAPMPowerCommandShutdown: { + asm volatile( + "ldr x0, =0x84000008\n" + "svc #0\n"); + + return kErrorSuccess; + } + default: + return kErrorInvalidData; + } +} diff --git a/dev/kernel/HALKit/ARM64/ApplicationProcessor.h b/dev/kernel/HALKit/ARM64/ApplicationProcessor.h new file mode 100644 index 00000000..d263f9b8 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/ApplicationProcessor.h @@ -0,0 +1,19 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <HALKit/ARM64/Processor.h> + +/************************************************** */ +/* INITIALIZE THE GIC ON CPU. */ +/************************************************** */ + +namespace NeOS +{ + BOOL mp_initialize_gic(NeOS::Void); +}
\ No newline at end of file diff --git a/dev/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc b/dev/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc new file mode 100644 index 00000000..a25112ae --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalACPIFactoryInterface.cc @@ -0,0 +1,32 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <NewKit/KString.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/MemoryMgr.h> +#include <modules/APM/APM.h> + +namespace NeOS +{ + ACPIFactoryInterface::ACPIFactoryInterface(VoidPtr rsp_ptr) + : fRsdp(rsp_ptr), fEntries(0) + { + } + + BOOL ACPIFactoryInterface::Shutdown() + { + apm_send_io_command(kAPMPowerCommandShutdown, 0); + return NO; + } + + /// @brief Reboot machine in either ACPI or by triple faulting. + /// @return nothing it's a reboot. + Void ACPIFactoryInterface::Reboot() + { + apm_send_io_command(kAPMPowerCommandReboot, 0); + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc b/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc new file mode 100644 index 00000000..660af502 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalApplicationProcessor.cc @@ -0,0 +1,145 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <HALKit/ARM64/Processor.h>
+#include <KernelKit/DebugOutput.h>
+#include <HALKit/ARM64/ApplicationProcessor.h>
+#include <KernelKit/UserProcessScheduler.h>
+
+#define GICD_BASE 0x08000000 // Distributor base address
+#define GICC_BASE 0x08010000 // CPU interface base address
+
+#define GICD_CTLR 0x000 // Distributor Control Register
+#define GICD_ISENABLER 0x100 // Interrupt Set-Enable Registers
+#define GICD_ICENABLER 0x180 // Interrupt Clear-Enable Registers
+#define GICD_ISPENDR 0x200 // Interrupt Set-Pending Registers
+#define GICD_ICPENDR 0x280 // Interrupt Clear-Pending Registers
+#define GICD_IPRIORITYR 0x400 // Interrupt Priority Registers
+#define GICD_ITARGETSR 0x800 // Interrupt Processor Targets Registers
+#define GICD_ICFGR 0xC00 // Interrupt Configuration Registers
+
+#define GICC_CTLR 0x000 // CPU Interface Control Register
+#define GICC_PMR 0x004 // Interrupt Priority Mask Register
+#define GICC_IAR 0x00C // Interrupt Acknowledge Register
+#define GICC_EOIR 0x010 // End of Interrupt Register
+
+// ================================================================= //
+
+namespace NeOS
+{
+ struct PROCESS_CONTROL_BLOCK final
+ {
+ HAL::StackFramePtr mFrame;
+ };
+
+ STATIC PROCESS_CONTROL_BLOCK kProcessBlocks[kSchedProcessLimitPerTeam] = {0};
+
+ namespace Detail
+ {
+ STATIC BOOL kGICEnabled = NO;
+
+ STATIC void mp_hang_fn(void)
+ {
+ while (YES)
+ ;
+
+ dbg_break_point();
+ }
+
+ Void mp_setup_gic_el0(Void)
+ {
+ // enable distributor.
+ ke_dma_write<UInt32>(GICD_BASE, GICD_CTLR, YES);
+
+ UInt32 gicc_ctlr = ke_dma_read<UInt32>(GICC_BASE, GICC_CTLR);
+
+ const auto kEnableSignalInt = YES;
+
+ gicc_ctlr |= kEnableSignalInt; // Enable signaling of interrupts
+ gicc_ctlr |= (kEnableSignalInt << 1); // Allow Group 1 interrupts in EL0
+
+ ke_dma_write<UInt32>(GICC_BASE, GICC_CTLR, gicc_ctlr);
+
+ // Set priority mask (accept all priorities)
+ ke_dma_write<UInt32>(GICC_BASE, GICC_PMR, 0xFF);
+
+ UInt32 icfgr = ke_dma_read<UInt32>(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4);
+
+ icfgr |= (0x2 << ((32 % 16) * 2)); // Edge-triggered
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ICFGR + (0x20 / 0x10) * 4, icfgr);
+
+ // Target interrupt 32 to CPU 1
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ITARGETSR + (0x20 / 0x04) * 4, 0x2 << ((32 % 4) * 8));
+
+ // Set interrupt 32 priority to lowest (0xFF)
+ ke_dma_write<UInt32>(GICD_BASE, GICD_IPRIORITYR + (0x20 / 0x04) * 4, 0xFF << ((32 % 4) * 8));
+
+ // Enable interrupt 32 for AP.
+ ke_dma_write<UInt32>(GICD_BASE, GICD_ISENABLER + 4, 0x01);
+ }
+
+ BOOL mp_handle_gic_interrupt_el0(Void)
+ {
+ // Read the interrupt ID
+ UInt32 interrupt_id = ke_dma_read<UInt32>(GICC_BASE, GICC_IAR);
+
+ // Check if it's a valid interrupt (not spurious)
+ if ((interrupt_id & 0x3FF) < 1020)
+ {
+ auto interrupt = interrupt_id & 0x3FF;
+
+ const UInt16 kInterruptScheduler = 0x20;
+
+ kout << "Handling interrupt for AP: " << interrupt << kendl;
+
+ switch (interrupt)
+ {
+ case kInterruptScheduler: {
+ ke_dma_write<UInt32>(GICC_BASE, GICC_EOIR, interrupt_id);
+ UserProcessHelper::StartScheduling();
+ break;
+ }
+ default: {
+ ke_dma_write<UInt32>(GICC_BASE, GICC_EOIR, interrupt_id);
+ break;
+ }
+ }
+
+ return YES;
+ }
+
+ // spurious interrupt
+ return NO;
+ }
+ } // namespace Detail
+
+ EXTERN_C HAL::StackFramePtr mp_get_current_context(ProcessID pid)
+ {
+ return kProcessBlocks[pid % kSchedProcessLimitPerTeam].mFrame;
+ }
+
+ EXTERN_C Bool mp_register_process(HAL::StackFramePtr stack_frame, ProcessID pid)
+ {
+ MUST_PASS(stack_frame);
+
+ const auto process_index = pid % kSchedProcessLimitPerTeam;
+
+ kProcessBlocks[process_index].mFrame = stack_frame;
+
+ return YES;
+ }
+
+ BOOL mp_initialize_gic(Void)
+ {
+ if (!Detail::kGICEnabled)
+ {
+ Detail::kGICEnabled = YES;
+ Detail::mp_setup_gic_el0();
+ }
+
+ return Detail::kGICEnabled;
+ }
+} // namespace NeOS
\ No newline at end of file diff --git a/dev/kernel/HALKit/ARM64/HalDebugOutput.cc b/dev/kernel/HALKit/ARM64/HalDebugOutput.cc new file mode 100644 index 00000000..8d54739f --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalDebugOutput.cc @@ -0,0 +1,83 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/DebugOutput.h> +#include <NewKit/Utils.h> +#include <NewKit/New.h> + +namespace NeOS +{ + EXTERN_C void ke_io_write(IDeviceObject<const Char*>* self, const Char* bytes) + { +#ifdef __DEBUG__ + if (*bytes == 0) + return; + + SizeT index = 0; + SizeT len = 0; + + index = 0; + len = rt_string_len(bytes, 256U); + + volatile UInt8* uart_ptr = (UInt8*)0x09000000; + + while (index < len) + { + if (bytes[index] == '\r') + *uart_ptr = '\r'; + + *uart_ptr = bytes[index] == '\r' ? '\n' : bytes[index]; + ++index; + } +#endif // __DEBUG__ + } + + TerminalDevice::~TerminalDevice() = default; + + EXTERN_C void ke_io_read(IDeviceObject<const Char*>* self, const Char* bytes) + { +#ifdef __DEBUG__ + SizeT index = 0; + + volatile UInt8* uart_ptr = (UInt8*)0x09000000; + + ///! TODO: Look on how to wait for the UART to complete. + while (Yes) + { + auto in = *uart_ptr; + + ///! If enter pressed then break. + if (in == 0xD) + { + break; + } + + if (in < '0' || in < 'A' || in < 'a') + { + if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || + in != ':') + { + continue; + } + } + + ((char*)bytes)[index] = in; + + ++index; + } + + ((char*)bytes)[index] = 0; +#endif // __DEBUG__ + } + + TerminalDevice TerminalDevice::The() noexcept + { + TerminalDevice out(NeOS::ke_io_write, NeOS::ke_io_read); + return out; + } + +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalFlushTLB.S b/dev/kernel/HALKit/ARM64/HalFlushTLB.S new file mode 100644 index 00000000..8fcf40ff --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalFlushTLB.S @@ -0,0 +1,5 @@ +.text + +hal_flush_tlb: + tlbi + ret diff --git a/dev/kernel/HALKit/ARM64/HalKernelMain.cc b/dev/kernel/HALKit/ARM64/HalKernelMain.cc new file mode 100644 index 00000000..55caca94 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalKernelMain.cc @@ -0,0 +1,54 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <modules/CoreGfx/FBMgr.h> +#include <FirmwareKit/Handover.h> +#include <KernelKit/FileMgr.h> +#include <KernelKit/MemoryMgr.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/UserProcessScheduler.h> +#include <NewKit/Json.h> +#include <KernelKit/CodeMgr.h> +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <NetworkKit/IPC.h> +#include <HALKit/ARM64/Processor.h> +#include <CFKit/Property.h> + +#include <HALKit/ARM64/ApplicationProcessor.h> + +EXTERN_C void hal_init_platform( + NeOS::HEL::BootInfoHeader* handover_hdr) +{ + + /************************************************** */ + /* INITIALIZE AND VALIDATE HEADER. */ + /************************************************** */ + + kHandoverHeader = handover_hdr; + + if (kHandoverHeader->f_Magic != kHandoverMagic && + kHandoverHeader->f_Version != kHandoverVersion) + { + return; + } + + /************************************** */ + /* INITIALIZE BIT MAP. */ + /************************************** */ + + kKernelBitMpSize = kHandoverHeader->f_BitMapSize; + kKernelBitMpStart = reinterpret_cast<NeOS::VoidPtr>( + reinterpret_cast<NeOS::UIntPtr>(kHandoverHeader->f_BitMapStart)); + + /// @note do initialize the interrupts after it. + + NeOS::mp_initialize_gic(); + + while (YES) + { + } +} diff --git a/dev/kernel/HALKit/ARM64/HalKernelPanic.cc b/dev/kernel/HALKit/ARM64/HalKernelPanic.cc new file mode 100644 index 00000000..5037f440 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalKernelPanic.cc @@ -0,0 +1,80 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/KernelPanic.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/Timer.h> +#include <KernelKit/DebugOutput.h> +#include <NewKit/KString.h> +#include <FirmwareKit/Handover.h> +#include <KernelKit/FileMgr.h> +#include <modules/CoreGfx/FBMgr.h> +#include <modules/CoreGfx/TextMgr.h> +#include <NewKit/Utils.h> + +/* Each error code is attributed with an ID, which will prompt a string onto the + * screen. Wait for debugger... */ + +namespace NeOS +{ + /// @brief Dumping factory class. + class RecoveryFactory final + { + public: + STATIC Void Recover() noexcept; + }; + + /***********************************************************************************/ + /// @brief Stops execution of the kernel. + /// @param id kernel stop ID. + /***********************************************************************************/ + Void ke_panic(const NeOS::Int32& id, const Char* message) + { + fb_init(); + + auto panic_text = RGB(0xff, 0xff, 0xff); + + auto y = 10; + auto x = 10; + + Char* message_apicid = new Char[128]; + rt_set_memory(message_apicid, 0, 128); + + rt_copy_memory((VoidPtr) "panic id: ", message_apicid, rt_string_len("panic id: ")); + rt_to_string(message_apicid + rt_string_len("panic id: "), (UIntPtr)id, 10); + + fb_render_string(message_apicid, y, x, panic_text); + + y += 10; + + fb_render_string((message ? message : "message: panic raised, going nowhere after this!"), y, x, panic_text); + + y += 10; + + fb_clear(); + + RecoveryFactory::Recover(); + } + + Void RecoveryFactory::Recover() noexcept + { + while (YES) + { + HAL::rt_halt(); + } + } + + void ke_runtime_check(bool expr, const Char* file, const Char* line) + { + if (!expr) + { + kout << "FAILED: FILE: " << file << kendl; + kout << "FAILED: LINE: " << line << kendl; + + ke_panic(RUNTIME_CHECK_FAILED, file); // Runtime Check failed + } + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalPagingMgrARM64.cc b/dev/kernel/HALKit/ARM64/HalPagingMgrARM64.cc new file mode 100644 index 00000000..4ec45b51 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalPagingMgrARM64.cc @@ -0,0 +1,86 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: HalPagingMgr.cc + Purpose: Platform Paging Manager. + +------------------------------------------- */ + +#include <HALKit/ARM64/Paging.h> +#include <HALKit/ARM64/Processor.h> + +namespace NeOS::HAL +{ + typedef UInt32 PageTableIndex; + + /// \brief Page store type. + struct NE_PAGE_STORE final + { + struct + { + PDE* fPde{nullptr}; + PTE* fPte{nullptr}; + VoidPtr fVAddr{nullptr}; + } fInternalStore; + + Bool fStoreOp{No}; // Store operation in progress. + + static NE_PAGE_STORE& The() + { + static NE_PAGE_STORE the; + return the; + } + }; + + /// \brief Retrieve the page status of a PTE. + STATIC Void mmi_page_status(PTE* pte) + { + } + + STATIC Int32 mmi_map_page_table_entry(VoidPtr virtual_address, UInt32 flags, PTE* pt_entry); + + /// @brief Maps or allocates a page from virtual_address. + /// @param virtual_address a valid virtual address. + /// @param phys_addr point to physical address. + /// @param flags the flags to put on the page. + /// @return Status code of page manipulation process. + EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags) + { + if (!virtual_address || + !flags) + return 0; + + NE_PAGE_STORE& page_store = NE_PAGE_STORE::The(); + + while (page_store.fStoreOp) + ; + + page_store.fStoreOp = Yes; + + if (page_store.fInternalStore.fVAddr == virtual_address) + { + page_store.fStoreOp = No; + return mmi_map_page_table_entry(page_store.fInternalStore.fVAddr, flags, page_store.fInternalStore.fPte); + } + + return 1; + } + + /// @brief Maps flags for a specific pte. + /// @internal Internal function. + STATIC Int32 mmi_map_page_table_entry(VoidPtr virtual_address, UInt32 flags, PTE* pt_entry) + { + NE_PAGE_STORE& page_store = NE_PAGE_STORE::The(); + + // Update internal store. + + page_store.fInternalStore.fPde = nullptr; + page_store.fInternalStore.fPte = pt_entry; + page_store.fInternalStore.fVAddr = virtual_address; + + page_store.fStoreOp = No; + + return 0; + } +} // namespace NeOS::HAL diff --git a/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc b/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc new file mode 100644 index 00000000..55c8aab5 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalSchedulerCoreARM64.cc @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + /// @brief Wakes up thread. + /// Wakes up thread from the hang state. + Void mp_wakeup_thread(HAL::StackFrame* stack) + { + NE_UNUSED(stack); + } + + /// @brief makes the thread sleep on a loop. + /// hooks and hangs thread to prevent code from executing. + Void mp_hang_thread(HAL::StackFrame* stack) + { + NE_UNUSED(stack); + } +} // namespace NeOS diff --git a/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc b/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc new file mode 100644 index 00000000..3a9b7074 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalSchedulerCorePrimitivesARM64.cc @@ -0,0 +1,35 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <HALKit/ARM64/Processor.h>
+#include <KernelKit/UserProcessScheduler.h>
+
+namespace NeOS
+{
+ /***********************************************************************************/
+ /// @brief Unimplemented function (crashes by default)
+ /// @param void
+ /***********************************************************************************/
+
+ EXTERN_C Void __zka_pure_call(UserProcess* process)
+ {
+ if (process)
+ process->Crash();
+ }
+
+ /***********************************************************************************/
+ /// @brief Validate user stack.
+ /// @param stack_ptr the frame pointer.
+ /***********************************************************************************/
+
+ EXTERN_C Bool hal_check_stack(HAL::StackFramePtr stack_ptr)
+ {
+ if (!stack_ptr)
+ return No;
+
+ return stack_ptr->SP != 0 && stack_ptr->BP != 0;
+ }
+} // namespace NeOS
diff --git a/dev/kernel/HALKit/ARM64/HalTimerARM64.cc b/dev/kernel/HALKit/ARM64/HalTimerARM64.cc new file mode 100644 index 00000000..785d2d5c --- /dev/null +++ b/dev/kernel/HALKit/ARM64/HalTimerARM64.cc @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: HalTimer.cc + Purpose: HAL timer + + Revision History: + + 07/07/24: Added file (amlel) + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> diff --git a/dev/kernel/HALKit/ARM64/MBCI/MBCI.cc b/dev/kernel/HALKit/ARM64/MBCI/MBCI.cc new file mode 100644 index 00000000..d2df66e6 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/MBCI/MBCI.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/MBCI/MBCI.h>
\ No newline at end of file diff --git a/dev/kernel/HALKit/ARM64/Paging.h b/dev/kernel/HALKit/ARM64/Paging.h new file mode 100644 index 00000000..3c24f757 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Paging.h @@ -0,0 +1,120 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +/** --------------------------------------------------- + + * THIS FILE CONTAINS CODE FOR ARMV8 PAGING. + +------------------------------------------------------- */ + +#include <NewKit/Defines.h> + +#ifndef kPageMax +#define kPageMax (0x200) +#endif //! kPageMax + +#ifndef kPageAlign +#define kPageAlign (0x1000) +#endif //! kPageAlign + +#ifndef kPageSize +#define kPageSize (0x1000) +#endif // !kPageSize + +//! short format address range + +#define c16KBPage 0b000 +#define c8KBPage 0b001 +#define c4KBPage 0b010 +#define c2KBPage 0b011 +#define c1KBPage 0b100 +#define c512BPage 0b101 +#define c256BPage 0b110 +#define c128BPage 0b111 + +/// Long format address range + +#define cPageMAll \ + { \ + 0b000, 0b000 \ + } +#define cPageMToMax(M) \ + { \ + M, 0b000 \ + } +#define cPageMaxToM(M) \ + { \ + 0b000, M \ + } +#define cPageMToN(M, N) \ + { \ + M, N \ + } + +namespace NeOS::HAL +{ + struct PACKED PTE_4KB final + { + UInt64 Valid : 1; + UInt64 Table : 1; + UInt64 AttrIndex : 3; + UInt64 NS : 1; + UInt64 AP : 2; + UInt64 SH : 2; + UInt64 AF : 1; + UInt64 NG : 1; + UInt64 Reserved1 : 1; + UInt64 Contiguous : 1; + UInt64 Dirty : 1; + UInt64 Reserved : 2; + UInt64 PhysicalAddress : 36; + UInt64 Reserved3 : 4; + UInt64 PXN : 1; + UInt64 XN : 1; + UInt64 Reserved4 : 9; + }; + + namespace Detail + { + enum class ControlRegisterBits + { + ProtectedModeEnable = 0, + MonitorCoProcessor = 1, + Emulation = 2, + TaskSwitched = 3, + ExtensionType = 4, + NumericError = 5, + WriteProtect = 16, + AlignementMask = 18, + NotWriteThrough = 29, + CacheDisable = 30, + PageEnable = 31, + }; + + inline UInt8 control_register_cast(ControlRegisterBits reg) + { + return static_cast<UInt8>(reg); + } + } // namespace Detail + + struct PDE_4KB final + { + PTE_4KB ALIGN(kPageAlign) fEntries[kPageMax]; + }; + + auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page) -> VoidPtr; + auto mm_free_bitmap(VoidPtr page_ptr) -> Bool; +} // namespace NeOS::HAL + +namespace NeOS +{ + typedef HAL::PTE_4KB PTE; + typedef HAL::PDE_4KB PDE; +} // namespace NeOS + +EXTERN_C void hal_flush_tlb(); diff --git a/dev/kernel/HALKit/ARM64/Processor.h b/dev/kernel/HALKit/ARM64/Processor.h new file mode 100644 index 00000000..940cfbe9 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Processor.h @@ -0,0 +1,91 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/Utils.h> +#include <FirmwareKit/Handover.h> + +#define kCPUBackendName "ARMv8" + +namespace NeOS::HAL +{ + struct PACKED Register64 final + { + UShort Limit; + UIntPtr Base; + }; + + /// @brief Memory Manager mapping flags. + enum + { + kMMFlagsPresent = 1 << 0, + kMMFlagsWr = 1 << 1, + kMMFlagsUser = 1 << 2, + kMMFlagsNX = 1 << 3, + kMMFlagsCount = 3, + }; + + /// @brief Set a PTE from pd_base. + /// @param virt_addr a valid virtual address. + /// @param phys_addr point to physical address. + /// @param flags the flags to put on the page. + /// @return Status code of page manip. + EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags); + + typedef UIntPtr Reg; + typedef Register64 Register; + + /// @note let's keep the same name as AMD64 HAL. + struct PACKED StackFrame final + { + Reg R8{0}; + Reg R9{0}; + Reg R10{0}; + Reg R11{0}; + Reg R12{0}; + Reg R13{0}; + Reg R14{0}; + Reg R15{0}; + Reg SP{0}; + Reg BP{0}; + }; + + typedef StackFrame* StackFramePtr; + + inline Void rt_halt() noexcept + { + while (Yes) + { + } + } + + template <typename DataKind> + inline void hal_dma_write(UIntPtr address, DataKind value) + { + *reinterpret_cast<volatile DataKind*>(address) = value; + } + + template <typename DataKind> + inline DataKind hal_dma_read(UIntPtr address) + { + return *reinterpret_cast<volatile DataKind*>(address); + } + + inline Void hal_wfi(Void) + { + asm volatile("wfi"); + } +} // namespace NeOS::HAL + +inline NeOS::VoidPtr kKernelBitMpStart = nullptr; +inline NeOS::UIntPtr kKernelBitMpSize = 0UL; + +inline NeOS::VoidPtr kKernelPhysicalStart = nullptr; + +#include <HALKit/ARM64/Paging.h> diff --git a/dev/kernel/HALKit/ARM64/ReadMe.md b/dev/kernel/HALKit/ARM64/ReadMe.md new file mode 100644 index 00000000..c51229f2 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/ReadMe.md @@ -0,0 +1,3 @@ +# ARM64 Hardware Abstraction Layer + +- Supported Firmware: CoreBoot/EDK/OpenMobileBoot diff --git a/dev/kernel/HALKit/ARM64/Storage/MBCI+Flash+IO+Generic.cc b/dev/kernel/HALKit/ARM64/Storage/MBCI+Flash+IO+Generic.cc new file mode 100644 index 00000000..94d20878 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Storage/MBCI+Flash+IO+Generic.cc @@ -0,0 +1,119 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef NE_USE_MBCI_FLASH + +#include <NewKit/Defines.h> +#include <ArchKit/ArchKit.h> +#include <modules/MFlash/MFlash.h> +#include <modules/MBCI/MBCI.h> + +/// @file MBCI+Flash.cc +/// @brief MBCI Flash support. + +#define MBCI_MAX_SLOTS (8U) + +namespace NeOS +{ + /// /Mount/Flash/n + constexpr auto kFlashBridgeMagic = 0x70768372; + constexpr auto kFlashBridgeRevision = 1; + + STATIC BOOL kFlashEnabled = NO; + STATIC SizeT kFlashSize[MBCI_MAX_SLOTS] = {}; + STATIC SizeT kFlashSectorSz[MBCI_MAX_SLOTS] = {}; + STATIC IMBCIHost* kFlashMetaPackets[MBCI_MAX_SLOTS] = {}; + STATIC IMBCIHost* kFlashDataPackets[MBCI_MAX_SLOTS] = {}; + + STATIC Void drv_std_io(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz); + + /// @brief Enable flash memory builtin. + STATIC Void drv_enable_flash(Int32 slot); + + /// @brief Disable flash memory builtin. + STATIC Void drv_disable_flash(Int32 slot); + + /// @brief get slot sector count. + /// @return slot sector count. + SizeT drv_get_sector_count(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return 0; + + return kFlashSectorSz[slot]; + } + + /// @brief get slot full size (in bytes). + /// @return drive slot size + SizeT drv_get_size(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return 0; + + return kFlashSize[slot]; + } + + /// @brief Enable flash memory at slot. + BOOL drv_enable_at(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return NO; + + kFlashMetaPackets[slot]->InterruptEnable = YES; + + kout << "Enabled hardware slot at: " << number(slot) << kendl; + + return YES; + } + + /// @brief Disable flash memory at slot. + BOOL drv_disable_at(Int32 slot) + { + if (slot > MBCI_MAX_SLOTS) + return NO; + + kFlashMetaPackets[slot]->InterruptEnable = NO; + + kout << "Disabled hardware slot at: " << number(slot) << kendl; + + return YES; + } + + STATIC Void drv_std_io(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz) + { + UInt64* packet_frame = (UInt64*)kFlashDataPackets[slot]->BaseAddressRegister; + + if (packet_frame[0] != (UInt64)kFlashBridgeMagic) + return; + + if (packet_frame[8] != (UInt64)kFlashBridgeRevision) + return; + + packet_frame[16 + 0] = lba; + packet_frame[16 + 4] = sector_sz; + packet_frame[16 + 8] = lba; + packet_frame[16 + 12] = buf_sz; + packet_frame[16 + 14] = (UIntPtr)HAL::hal_get_phys_address(buf); + + while (packet_frame[0] == lba) + ; + } + + Void drv_std_read(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz) + { + rt_set_memory(buf, 0, buf_sz); + + drv_std_io(slot, lba, buf, sector_sz, buf_sz); + } + + Void drv_std_write(Int32 slot, UInt64 lba, Char* buf, SizeT sector_sz, SizeT buf_sz) + { + drv_std_io(slot, lba, buf, sector_sz, buf_sz); + } + +} // namespace NeOS + +#endif // if NE_USE_MBCI_FLASH diff --git a/dev/kernel/HALKit/ARM64/Storage/UFS+Generic.cc b/dev/kernel/HALKit/ARM64/Storage/UFS+Generic.cc new file mode 100644 index 00000000..20d06671 --- /dev/null +++ b/dev/kernel/HALKit/ARM64/Storage/UFS+Generic.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/// @file UFS.cc +/// @brief UFS Flash Memory support. + +#define UFS_PCI_VENDOR_ID (0x01001) /* AKER */ +#define UFS_PCI_DEVICE_ID (0xAEAEA) /* AKER */
\ No newline at end of file diff --git a/dev/kernel/HALKit/AXP/CR.s b/dev/kernel/HALKit/AXP/CR.s new file mode 100644 index 00000000..4d68257d --- /dev/null +++ b/dev/kernel/HALKit/AXP/CR.s @@ -0,0 +1,11 @@ +.globl read_lr1 +.globl read_lr0 + +.section .text + read_lr0: + movq %r30, %cr3 + ret + + hal_read_cr0: + movq %r30, %cr0 + ret
\ No newline at end of file diff --git a/dev/kernel/HALKit/AXP/CoreInterruptHandlerDEC.cpp b/dev/kernel/HALKit/AXP/CoreInterruptHandlerDEC.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/AXP/CoreInterruptHandlerDEC.cpp diff --git a/dev/kernel/HALKit/AXP/CoreSyscallHandlerDEC.cpp b/dev/kernel/HALKit/AXP/CoreSyscallHandlerDEC.cpp new file mode 100644 index 00000000..f77186fd --- /dev/null +++ b/dev/kernel/HALKit/AXP/CoreSyscallHandlerDEC.cpp @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <HALKit/AXP/Processor.h> + +/// @brief Internal call for syscall, to work with C++. +/// @param stack +/// @return nothing. +EXTERN_C void rt_syscall_handle(NeOS::HAL::StackFrame* stack) +{ + if (stack->Rcx <= (kSyscalls.Count() - 1)) + { + kout << "syscall: enter.\r"; + + if (kSyscalls[stack->Rcx].Leak().Leak().fHooked) + (kSyscalls[stack->Rcx].Leak().Leak().fProc)(stack); + + kout << "syscall: exit.\r"; + } +} diff --git a/dev/kernel/HALKit/AXP/HAL.s b/dev/kernel/HALKit/AXP/HAL.s new file mode 100644 index 00000000..0178527f --- /dev/null +++ b/dev/kernel/HALKit/AXP/HAL.s @@ -0,0 +1,13 @@ +.globl rt_wait_400ns + +.section .text +rt_wait_400ns: + jmp .L +.L: + jmp .L2 + wtint ;; wait for interrupt +.L2: + + ret + + diff --git a/dev/kernel/HALKit/AXP/Processor.h b/dev/kernel/HALKit/AXP/Processor.h new file mode 100644 index 00000000..bb14c9c6 --- /dev/null +++ b/dev/kernel/HALKit/AXP/Processor.h @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once diff --git a/dev/kernel/HALKit/AXP/SYSCALL.s b/dev/kernel/HALKit/AXP/SYSCALL.s new file mode 100644 index 00000000..19cab808 --- /dev/null +++ b/dev/kernel/HALKit/AXP/SYSCALL.s @@ -0,0 +1,10 @@ +.section .text +system_handle_user_call: + .cfi_startproc + + push %r0 + jmp %r1 + mov %r30, %r2 + + .cfi_endproc + retsys
\ No newline at end of file diff --git a/dev/kernel/HALKit/AXP/VM.s b/dev/kernel/HALKit/AXP/VM.s new file mode 100644 index 00000000..7024086b --- /dev/null +++ b/dev/kernel/HALKit/AXP/VM.s @@ -0,0 +1,5 @@ +.global hal_flush_tlb + +.section .text +hal_flush_tlb: + swppal
\ No newline at end of file diff --git a/dev/kernel/HALKit/POWER/.gitkeep b/dev/kernel/HALKit/POWER/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/POWER/.gitkeep diff --git a/dev/kernel/HALKit/POWER/AP.h b/dev/kernel/HALKit/POWER/AP.h new file mode 100644 index 00000000..e0ef3ffb --- /dev/null +++ b/dev/kernel/HALKit/POWER/AP.h @@ -0,0 +1,39 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: AP.h + Purpose: POWER hardware threads. + + Revision History: + + 14/04/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + struct HAL_HARDWARE_THREAD; + + /// @brief hardware thread indentification type. + typedef NeOS::Int32 hal_ap_kind; + + /// @brief Hardware thread information structure. + typedef struct HAL_HARDWARE_THREAD + { + NeOS::UIntPtr fStartAddress; + NeOS::UInt8 fPrivleged : 1; + NeOS::UInt32 fPageMemoryFlags; + hal_ap_kind fIdentNumber; + } HAL_HARDWARE_THREAD; + + /// @brief Set PC to specific hart. + /// @param hart the hart + /// @param epc the pc. + /// @return + EXTERN_C NeOS::Void hal_set_pc_to_hart(HAL_HARDWARE_THREAD* hart, NeOS::VoidPtr epc); +} // namespace NeOS diff --git a/dev/kernel/HALKit/POWER/APM/.gitkeep b/dev/kernel/HALKit/POWER/APM/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/POWER/APM/.gitkeep diff --git a/dev/kernel/HALKit/POWER/HalAP.cc b/dev/kernel/HALKit/POWER/HalAP.cc new file mode 100644 index 00000000..32f91a5f --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalAP.cc @@ -0,0 +1,40 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> +#include <HALKit/POWER/AP.h> + +using namespace NeOS; + +namespace NeOS::Detail +{ + STATIC void mp_hang_fn(void) + { + while (YES) + ; + } +} // namespace NeOS::Detail + +/// @brief wakes up thread. +/// wakes up thread from hang. +void mp_wakeup_thread(HAL::StackFramePtr stack) +{ + if (!stack) + return; + + hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(stack->BP)); +} + +/// @brief makes thread sleep. +/// hooks and hangs thread to prevent code from executing. +void mp_hang_thread(HAL::StackFramePtr stack) +{ + if (!stack) + return; + + hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(NeOS::Detail::mp_hang_fn)); +} diff --git a/dev/kernel/HALKit/POWER/HalDebugOutput.cc b/dev/kernel/HALKit/POWER/HalDebugOutput.cc new file mode 100644 index 00000000..e9b2c85a --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalDebugOutput.cc @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> + +using namespace NeOS; + +/// @brief Writes to COM1. +/// @param bytes +void ke_io_write(const Char* bytes) +{ + if (!bytes) + return; + + SizeT index = 0; + SizeT len = rt_string_len(bytes, 256U); + + while (index < len) + { + // TODO + ++index; + } +} diff --git a/dev/kernel/HALKit/POWER/HalStartSequence.s b/dev/kernel/HALKit/POWER/HalStartSequence.s new file mode 100644 index 00000000..2882be80 --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalStartSequence.s @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +.globl __ImageStart +.extern hal_init_platform +.align 4 +.text + +__ImageStart: + bl hal_init_platform + blr diff --git a/dev/kernel/HALKit/POWER/HalThread.cc b/dev/kernel/HALKit/POWER/HalThread.cc new file mode 100644 index 00000000..0d2e140b --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalThread.cc @@ -0,0 +1,8 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> diff --git a/dev/kernel/HALKit/POWER/HalVirtualMemory.cc b/dev/kernel/HALKit/POWER/HalVirtualMemory.cc new file mode 100644 index 00000000..d3d4b694 --- /dev/null +++ b/dev/kernel/HALKit/POWER/HalVirtualMemory.cc @@ -0,0 +1,49 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> +#include <HALKit/POWER/MMU.h> + +/// @note Refer to SoC documentation. + +using namespace NeOS; + +EXTERN_C Void hal_write_tlb(UInt32 mas0, UInt32 mas1, UInt32 mas2, UInt32 mas3, UInt32 mas7) +{ + hal_mtspr(MAS0, mas0); + hal_mtspr(MAS1, mas1); + hal_mtspr(MAS2, mas2); + hal_mtspr(MAS3, mas3); + hal_mtspr(MAS7, mas7); + + hal_flush_tlb(); +} + +EXTERN_C Bool hal_set_tlb(UInt8 tlb, UInt32 epn, UInt64 rpn, UInt8 perms, UInt8 wimge, UInt8 ts, UInt8 esel, UInt8 tsize, UInt8 iprot) +{ + if ((hal_mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1 && (tsize & 1)) + { + // this MMU does not allow odd tsize values + return false; + } + + UInt32 mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); + UInt32 mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); + UInt32 mas2 = FSL_BOOKE_MAS2(epn, wimge); + UInt32 mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); + UInt32 mas7 = FSL_BOOKE_MAS7(rpn); + + hal_write_tlb(mas0, mas1, mas2, mas3, mas7); + + return true; +} + +/// @brief Flush TLB +EXTERN_C void hal_flush_tlb() +{ + asm volatile("isync;tlbwe;msync;isync"); +} diff --git a/dev/kernel/HALKit/POWER/MBCI/.gitkeep b/dev/kernel/HALKit/POWER/MBCI/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/POWER/MBCI/.gitkeep diff --git a/dev/kernel/HALKit/POWER/MBCI/HalMBCIHost.cc b/dev/kernel/HALKit/POWER/MBCI/HalMBCIHost.cc new file mode 100644 index 00000000..0d2e140b --- /dev/null +++ b/dev/kernel/HALKit/POWER/MBCI/HalMBCIHost.cc @@ -0,0 +1,8 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <HALKit/POWER/Processor.h> +#include <KernelKit/DebugOutput.h> diff --git a/dev/kernel/HALKit/POWER/Processor.h b/dev/kernel/HALKit/POWER/Processor.h new file mode 100644 index 00000000..bbcfd01f --- /dev/null +++ b/dev/kernel/HALKit/POWER/Processor.h @@ -0,0 +1,62 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + Purpose: POWER processor header. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/Utils.h> + +#define NoOp() asm volatile("mr 0, 0") +#define kHalPPCAlignment __attribute__((aligned(4))) + +namespace NeOS::HAL +{ + typedef UIntPtr Reg; + + /// @brief Stack frame (as retrieved from assembly.) + struct PACKED StackFrame final + { + Reg R8{0}; + Reg R9{0}; + Reg R10{0}; + Reg R11{0}; + Reg R12{0}; + Reg R13{0}; + Reg R14{0}; + Reg R15{0}; + Reg SP{0}; + Reg BP{0}; + }; + + typedef StackFrame* StackFramePtr; + + inline void rt_halt() + { + while (true) + { + NoOp(); // no oop. + } + } + + inline void rt_cli() + { + NoOp(); // no oop + } +} // namespace NeOS::HAL + +EXTERN_C NeOS::Void int_handle_math(NeOS::UIntPtr sp); +EXTERN_C NeOS::Void int_handle_pf(NeOS::UIntPtr sp); + +/// @brief Set TLB. +NeOS::Bool hal_set_tlb(NeOS::UInt8 tlb, NeOS::UInt32 epn, NeOS::UInt64 rpn, NeOS::UInt8 perms, NeOS::UInt8 wimge, NeOS::UInt8 ts, NeOS::UInt8 esel, NeOS::UInt8 tsize, NeOS::UInt8 iprot); + +/// @brief Write TLB. +NeOS::Void hal_write_tlb(NeOS::UInt32 mas0, NeOS::UInt32 mas1, NeOS::UInt32 mas2, NeOS::UInt32 mas3, NeOS::UInt32 mas7); + +/// @brief Flush TLB. +EXTERN_C NeOS::Void hal_flush_tlb(); diff --git a/dev/kernel/HALKit/POWER/ReadMe.md b/dev/kernel/HALKit/POWER/ReadMe.md new file mode 100644 index 00000000..a9751581 --- /dev/null +++ b/dev/kernel/HALKit/POWER/ReadMe.md @@ -0,0 +1,4 @@ +POWER Hardware Abstraction Layer + +- Supported CPU: POWER +- Supported Firmware: CoreBoot
\ No newline at end of file diff --git a/dev/kernel/HALKit/RISCV/.keep b/dev/kernel/HALKit/RISCV/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/RISCV/.keep diff --git a/dev/kernel/HALKit/RISCV/AP.h b/dev/kernel/HALKit/RISCV/AP.h new file mode 100644 index 00000000..c198a404 --- /dev/null +++ b/dev/kernel/HALKit/RISCV/AP.h @@ -0,0 +1,35 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: AP.h + Purpose: RISC-V hardware threads. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + typedef Int64 hal_ap_kind; + + typedef struct HAL_HARDWARE_THREAD + { + NeOS::UIntPtr fStartAddress; + NeOS::UInt8 fPrivleged : 1; + NeOS::UInt32 fPageMemoryFlags; + hal_ap_kind fIdentNumber; + } HAL_HARDWARE_THREAD; + + /// @brief Set PC to specific hart. + /// @param hart the hart + /// @param epc the pc. + /// @return + EXTERN_C NeOS::Void hal_set_pc_to_hart(HAL_HARDWARE_THREAD* hart, NeOS::VoidPtr epc); +} // namespace NeOS diff --git a/dev/kernel/HALKit/RISCV/APM/.gitkeep b/dev/kernel/HALKit/RISCV/APM/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/RISCV/APM/.gitkeep diff --git a/dev/kernel/HALKit/RISCV/HalAP.cc b/dev/kernel/HALKit/RISCV/HalAP.cc new file mode 100644 index 00000000..788acf0f --- /dev/null +++ b/dev/kernel/HALKit/RISCV/HalAP.cc @@ -0,0 +1,40 @@ +/* -------------------------------------------
+
+ Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.
+
+------------------------------------------- */
+
+#include <HALKit/RISCV/Processor.h>
+#include <KernelKit/DebugOutput.h>
+#include <HALKit/RISCV/AP.h>
+
+using namespace NeOS;
+
+namespace NeOS::Detail
+{
+ STATIC void mp_hang_fn(void)
+ {
+ while (YES)
+ ;
+ }
+} // namespace NeOS::Detail
+
+/// @brief wakes up thread.
+/// wakes up thread from hang.
+void mp_wakeup_thread(HAL::StackFramePtr stack)
+{
+ if (!stack)
+ return;
+
+ hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(stack->BP));
+}
+
+/// @brief makes thread sleep.
+/// hooks and hangs thread to prevent code from executing.
+void mp_hang_thread(HAL::StackFramePtr stack)
+{
+ if (!stack)
+ return;
+
+ hal_set_pc_to_hart(reinterpret_cast<HAL_HARDWARE_THREAD*>(stack->R15), reinterpret_cast<VoidPtr>(NeOS::Detail::mp_hang_fn));
+}
diff --git a/dev/kernel/HALKit/RISCV/ReadMe.md b/dev/kernel/HALKit/RISCV/ReadMe.md new file mode 100644 index 00000000..b099aa31 --- /dev/null +++ b/dev/kernel/HALKit/RISCV/ReadMe.md @@ -0,0 +1,4 @@ +RISCV64 Hardware Abstraction Layer + +- Supported CPU: RISCV64 +- Supported Firmware: CoreBoot
\ No newline at end of file diff --git a/dev/kernel/HALKit/RISCV/Storage/.gitkeep b/dev/kernel/HALKit/RISCV/Storage/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/RISCV/Storage/.gitkeep diff --git a/dev/kernel/HALKit/X86S/.gitkeep b/dev/kernel/HALKit/X86S/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/X86S/.gitkeep diff --git a/dev/kernel/HALKit/X86S/ACPI/.gitkeep b/dev/kernel/HALKit/X86S/ACPI/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/X86S/ACPI/.gitkeep diff --git a/dev/kernel/HALKit/X86S/Storage/.gitkeep b/dev/kernel/HALKit/X86S/Storage/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/HALKit/X86S/Storage/.gitkeep diff --git a/dev/kernel/KernelKit/BinaryMutex.h b/dev/kernel/KernelKit/BinaryMutex.h new file mode 100644 index 00000000..21b2ca6d --- /dev/null +++ b/dev/kernel/KernelKit/BinaryMutex.h @@ -0,0 +1,43 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <KernelKit/Timer.h> +#include <CompilerKit/CompilerKit.h> + +namespace NeOS +{ + class UserProcess; + + typedef UserProcess& UserProcessRef; + + /// @brief Access control class, which locks a task until one is done. + class BinaryMutex final + { + public: + explicit BinaryMutex() = default; + ~BinaryMutex() = default; + + public: + bool IsLocked() const; + bool Unlock() noexcept; + + public: + BOOL WaitForProcess(const Int16& sec) noexcept; + + public: + bool Lock(UserProcess& process); + bool LockOrWait(UserProcess& process, TimerInterface* timer); + + public: + NE_COPY_DEFAULT(BinaryMutex); + + private: + UserProcessRef fLockingProcess; + }; +} // namespace NeOS diff --git a/dev/kernel/KernelKit/CodeMgr.h b/dev/kernel/KernelKit/CodeMgr.h new file mode 100644 index 00000000..5f83c74b --- /dev/null +++ b/dev/kernel/KernelKit/CodeMgr.h @@ -0,0 +1,37 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: CodeMgr.h + Purpose: Code Mgr. + + Revision History: + + 30/01/24: Added file (amlel) + 3/8/24: Add UPP struct. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/PECodeMgr.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/IPEFDylibObject.h> + +namespace NeOS +{ + /// @brief Main process entrypoint. + typedef void (*rtl_main_kind)(const SizeT argc, Char** argv, Char** envp, const SizeT envp_len); + + /// @brief C++ Constructor entrypoint. + typedef void (*rtl_ctor_kind)(void); + + /// @brief C++ Destructor entrypoint. + typedef void (*rtl_dtor_kind)(void); + + /// @brief Executes a new process from a function. Kernel code only. + /// @note This sets up a new stack, anything on the main function that calls the Kernel will not be accessible. + /// @param main the start of the process. + /// @return The team's process id. + ProcessID rtl_create_process(rtl_main_kind main, const Char* process_name) noexcept; +} // namespace NeOS diff --git a/dev/kernel/KernelKit/DebugOutput.h b/dev/kernel/KernelKit/DebugOutput.h new file mode 100644 index 00000000..cfadd38d --- /dev/null +++ b/dev/kernel/KernelKit/DebugOutput.h @@ -0,0 +1,213 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/DeviceMgr.h> +#include <CompilerKit/CompilerKit.h> +#include <NewKit/OwnPtr.h> +#include <NewKit/Stream.h> + +#define kDebugMaxPorts 56 + +#define kDebugUnboundPort 0x0FEED + +#define kDebugMag0 'Z' +#define kDebugMag1 'D' +#define kDebugMag2 'B' +#define kDebugMag3 'G' + +#define kDebugSourceFile 0 +#define kDebugLine 33 +#define kDebugTeam 43 +#define kDebugEOP 49 + +namespace NeOS +{ + class TerminalDevice; + class DTraceDevice; + + inline TerminalDevice end_line(); + inline TerminalDevice number(const Long& x); + inline TerminalDevice hex_number(const Long& x); + + // @brief Emulates a VT100 terminal. + class TerminalDevice final NE_DEVICE<const Char*> + { + public: + TerminalDevice(void (*print)(IDeviceObject*, const Char*), void (*gets)(IDeviceObject*, const Char*)) + : IDeviceObject<const Char*>(print, gets) + { + } + + ~TerminalDevice() override; + + /// @brief returns device name (terminal name) + /// @return string type (const Char*) + const Char* Name() const override + { + return ("TerminalDevice"); + } + + NE_COPY_DEFAULT(TerminalDevice); + + STATIC TerminalDevice The() noexcept; + }; + + inline TerminalDevice end_line() + { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\r"); + return self; + } + + inline TerminalDevice carriage_return() + { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\r"); + return self; + } + + inline TerminalDevice tabulate() + { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\t"); + return self; + } + + /// @brief emulate a terminal bell, like the VT100 does. + inline TerminalDevice bell() + { + TerminalDevice self = TerminalDevice::The(); + + self.operator<<("\a"); + return self; + } + + namespace Detail + { + inline TerminalDevice _write_number(const Long& x, TerminalDevice& term) + { + UInt64 y = (x > 0 ? x : -x) / 10; + UInt64 h = (x > 0 ? x : -x) % 10; + + if (y) + _write_number(y, term); + + /* fail if the number is not base-10 */ + if (h > 10) + { + _write_number('?', term); + return term; + } + + if (y < 0) + y = -y; + + const Char kNumbers[11] = "0123456789"; + + Char buf[2]; + buf[0] = kNumbers[h]; + buf[1] = 0; + + term.operator<<(buf); + return term; + } + + inline TerminalDevice _write_number_hex(const Long& x, TerminalDevice& term) + { + UInt64 y = (x > 0 ? x : -x) / 16; + UInt64 h = (x > 0 ? x : -x) % 16; + + if (y) + _write_number_hex(y, term); + + /* fail if the hex number is not base-16 */ + if (h > 16) + { + _write_number_hex('?', term); + return term; + } + + if (y < 0) + y = -y; + + const Char kNumbers[17] = "0123456789ABCDEF"; + + Char buf[2]; + buf[0] = kNumbers[h]; + buf[1] = 0; + + term.operator<<(buf); + return term; + } + } // namespace Detail + + inline TerminalDevice hex_number(const Long& x) + { + TerminalDevice self = TerminalDevice::The(); + + Detail::_write_number_hex(x, self); + self.operator<<("h"); + + return self; + } + + inline TerminalDevice number(const Char* x) + { + TerminalDevice self = TerminalDevice::The(); + + self << "?"; + + return self; + } + + inline TerminalDevice number(const Long& x) + { + TerminalDevice self = TerminalDevice::The(); + + Detail::_write_number(x, self); + + return self; + } + + inline TerminalDevice get_console_in(Char* buf) + { + TerminalDevice self = TerminalDevice::The(); + + self >> buf; + + return self; + } + + constexpr SizeT kDebugTypeLen = 256U; + + typedef Char rt_debug_type[kDebugTypeLen]; + + class DebuggerPortHeader final + { + public: + Int16 fPort[kDebugMaxPorts]; + Int16 fPortCnt; + }; + + inline TerminalDevice& operator<<(TerminalDevice& src, const Long& num) + { + src = number(num); + return src; + } +} // namespace NeOS + +#ifdef kout +#undef kout +#endif // ifdef kout + +#define kout NeOS::TerminalDevice::The() << "[NeKernel] *" << __FILE__ << "*: " + +#define kendl NeOS::TerminalDevice::The() << NeOS::end_line() diff --git a/dev/kernel/KernelKit/Defines.h b/dev/kernel/KernelKit/Defines.h new file mode 100644 index 00000000..d86988a7 --- /dev/null +++ b/dev/kernel/KernelKit/Defines.h @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +#define KERNELKIT_VERSION "1.0.2" +#define KERNELKIT_VERSION_BCD 0x01020 + +class UserProcessScheduler; +class UserProcess; diff --git a/dev/kernel/KernelKit/DeviceMgr.h b/dev/kernel/KernelKit/DeviceMgr.h new file mode 100644 index 00000000..fa68d2e7 --- /dev/null +++ b/dev/kernel/KernelKit/DeviceMgr.h @@ -0,0 +1,140 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/* ------------------------------------------- + + Revision History: + + 31/01/24: Add kDeviceCnt (amlel) + 15/11/24: Add NE_DEVICE macro, to inherit from device object. + + ------------------------------------------- */ + +#pragma once + +/* @note Device Mgr. */ +/* @file KernelKit/DeviceMgr.h */ +/* @brief Device abstraction and I/O buffer. */ + +#include <NewKit/ErrorOr.h> +#include <NewKit/Ref.h> + +#define kDeviceMgrRootDirPath "/Devices/" + +#define NE_DEVICE : public ::NeOS::IDeviceObject + +// Last Rev: Wed, Apr 3, 2024 9:09:41 AM + +namespace NeOS +{ + template <typename T> + class IDeviceObject; + + /***********************************************************************************/ + /// @brief Device contract interface, represents an HW device. + /***********************************************************************************/ + template <typename T> + class IDeviceObject + { + public: + explicit IDeviceObject(void (*Out)(IDeviceObject<T>*, T), void (*In)(IDeviceObject<T>*, T)) + : fOut(Out), fIn(In) + { + } + + virtual ~IDeviceObject() = default; + + public: + IDeviceObject& operator=(const IDeviceObject<T>&) = default; + IDeviceObject(const IDeviceObject<T>&) = default; + + public: + virtual IDeviceObject<T>& operator<<(T Data) + { + fOut(this, Data); + return *this; + } + + virtual IDeviceObject<T>& operator>>(T Data) + { + fIn(this, Data); + return *this; + } + + virtual const char* Name() const + { + return "/dev/null"; + } + + operator bool() + { + return fOut && fIn; + } + + Bool operator!() + { + return !fOut || !fIn; + } + + protected: + Void (*fOut)(IDeviceObject<T>*, T Data) = {nullptr}; + Void (*fIn)(IDeviceObject<T>*, T Data) = {nullptr}; + }; + + /// + /// @brief Input Output abstract class. + /// Used mainly to communicate between OS to hardware. + /// + template <typename T> + class IOBuf final + { + public: + explicit IOBuf(T dma_addr) + : fData(dma_addr) + { + // At least pass something valid when instancating this struct. + MUST_PASS(fData); + } + + IOBuf& operator=(const IOBuf<T>&) = default; + IOBuf(const IOBuf<T>&) = default; + + ~IOBuf() = default; + + public: + template <typename R> + R operator->() const + { + return fData; + } + + template <typename R> + R& operator[](Size index) const + { + return fData[index]; + } + + private: + T fData; + }; + + ///! @brief Device enum types. + enum + { + kDeviceTypeIDE, + kDeviceTypeEthernet, + kDeviceTypeWiFi, + kDeviceTypeFW, + kDeviceTypeBT, + kDeviceTypeRS232, + kDeviceTypeSCSI, + kDeviceTypeAHCI, + kDeviceTypeMBCI, + kDeviceTypeUSB, + kDeviceTypeMediaCtrl, // MM controller + kDeviceTypeCount, + }; +} // namespace NeOS diff --git a/dev/kernel/KernelKit/DriveMgr.h b/dev/kernel/KernelKit/DriveMgr.h new file mode 100644 index 00000000..87bd2714 --- /dev/null +++ b/dev/kernel/KernelKit/DriveMgr.h @@ -0,0 +1,191 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef INC_DRIVE_MANAGER_H +#define INC_DRIVE_MANAGER_H + +#include <KernelKit/UserProcessScheduler.h> +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/DebugOutput.h> +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/LPC.h> +#include <NewKit/Defines.h> +#include <NewKit/KString.h> +#include <NewKit/Ref.h> + +#define kDriveMaxCount (4U) +#define kDriveSectorSz (512U) +#define kDriveInvalidID (-1) +#define kDriveNameLen (32) + +#define drv_sector_cnt(SIZE, SECTOR_SZ) (((SIZE) + (SECTOR_SZ)) / (SECTOR_SZ)) + +namespace NeOS +{ + enum + { + kInvalidDrive = -1, + + /// Storage types, combine with flags. + kBlockDevice = 0xAD, + kMassStorageDrive = 0xDA, + kFloppyDrive = 0xCD, + kOpticalDrive = 0xDC, // CD-ROM/DVD-ROM/Blu-Ray + kTapeDrive = 0xD7, + + /// Storage flags, combine with types. + kReadOnlyDrive = 0x10, // Read only drive + kEPMDrive = 0x11, // Explicit Partition Map. + kEPTDrive = 0x12, // ESP w/ EPM partition. + kMBRDrive = 0x13, // PC classic partition scheme + kGPTDrive = 0x14, // PC new partition scheme + kUnformattedDrive = 0x15, + kStorageCount = 9, + }; + + /// @brief Media drive trait type. + struct DriveTrait final + { + Char fName[kDriveNameLen]; // /System, /boot, //./Devices/USB... + Int32 fKind; // fMassStorage, fFloppy, fOpticalDrive. + Int32 fFlags; // fReadOnly, fEPMDrive... + + /// @brief Packet drive (StorageKit compilant.) + struct DrivePacket final + { + VoidPtr fPacketContent{nullptr}; //! packet body. + Char fPacketMime[kDriveNameLen] = "*/*"; //! identify what we're sending. + SizeT fPacketSize{0UL}; //! packet size + UInt32 fPacketCRC32{0UL}; //! sanity crc, in case if good is set to false + Boolean fPacketGood{YES}; + Lba fPacketLba{0UL}; + Boolean fPacketReadOnly{NO}; + } fPacket; + + Lba fLbaStart{0}, fLbaEnd{0}; + SizeT fSectorSz{512}; + + Void (*fInput)(DrivePacket packet); + Void (*fOutput)(DrivePacket packet); + Void (*fVerify)(DrivePacket packet); + Void (*fInit)(DrivePacket packet); + const Char* (*fDriveKind)(Void); + }; + + ///! drive as a device. + typedef DriveTrait* DriveTraitPtr; + + /** + * @brief Mounted drives interface. + * @note This class has all of it's drive set to nullptr, allocate them using + * GetAddressOf(index). + */ + class MountpointInterface final + { + public: + explicit MountpointInterface() = default; + ~MountpointInterface() = default; + + NE_COPY_DEFAULT(MountpointInterface); + + public: + DriveTrait& A() + { + return mA; + } + + DriveTrait& B() + { + return mB; + } + + DriveTrait& C() + { + return mC; + } + + DriveTrait& D() + { + return mD; + } + + enum + { + kDriveIndexA = 0, + kDriveIndexB, + kDriveIndexC, + kDriveIndexD, + kDriveIndexInvalid, + }; + + DriveTraitPtr GetAddressOf(const Int32& index) + { + err_local_get() = kErrorSuccess; + + switch (index) + { + case kDriveIndexA: + return &mA; + case kDriveIndexB: + return &mB; + case kDriveIndexC: + return &mC; + case kDriveIndexD: + return &mD; + default: { + err_local_get() = kErrorNoSuchDisk; + kout << "No such disc letter.\n"; + + break; + } + } + + return nullptr; + } + + private: + DriveTrait mA, mB, mC, mD; + }; + + /// @brief Unimplemented drive. + /// @param pckt the packet to read. + /// @return + Void io_drv_unimplemented(DriveTrait::DrivePacket* pckt) noexcept; + + /// @brief Gets the drive kind (ATA, SCSI, AHCI...) + /// @param void none. + /// @return the drive kind (ATA, Flash, NVM) + const Char* io_drv_kind(Void); + + /// @brief Makes a new drive. + /// @return the new drive as a trait. + DriveTrait io_construct_blank_drive(Void) noexcept; + + /// @brief Fetches the main drive. + /// @return the new drive as a trait. + DriveTrait io_construct_main_drive(Void) noexcept; + + namespace Detect + { + Void io_detect_drive(DriveTrait& trait); + } + + /// @brief Read from newfs disk. + /// @param Mnt mounted interface. + /// @param DrvTrait drive info + /// @param DrvIndex drive index. + /// @return + Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); + + /// @brief Write to ifs disk. + /// @param Mnt mounted interface. + /// @param DrvTrait drive info + /// @param DrvIndex drive index. + /// @return + Int32 fs_ifs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); +} // namespace NeOS + +#endif /* ifndef INC_DRIVE_MANAGER_H */ diff --git a/dev/kernel/KernelKit/FileMgr.h b/dev/kernel/KernelKit/FileMgr.h new file mode 100644 index 00000000..7374df9d --- /dev/null +++ b/dev/kernel/KernelKit/FileMgr.h @@ -0,0 +1,392 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss Labs, all rights reserved. + + File: FileMgr.h + Purpose: Kernel file manager. + +------------------------------------------- */ + +/* ------------------------------------------- + + Revision History: + + 31/01/24: Update documentation (amlel) + 05/07/24: NeFS support, and fork support, updated constants and specs + as well. + 18/01/25: Patches to FileStream class. + + ------------------------------------------- */ + +#ifndef INC_FILEMGR_H +#define INC_FILEMGR_H + +#ifdef __FSKIT_INCLUDES_NEFS__ +#include <FSKit/NeFS.h> +#endif // __FSKIT_INCLUDES_NEFS__ + +#ifdef __FSKIT_INCLUDES_HeFS__ +#include <FSKit/HeFS.h> +#endif // __FSKIT_INCLUDES_HeFS__ + +#include <CompilerKit/CompilerKit.h> +#include <HintsKit/CompilerHint.h> +#include <KernelKit/LPC.h> +#include <KernelKit/DebugOutput.h> +#include <NewKit/Stream.h> +#include <NewKit/ErrorOr.h> +#include <KernelKit/MemoryMgr.h> +#include <NewKit/Ref.h> + +/// @brief Filesystem manager, abstraction over mounted filesystem. +/// Works like the VFS or IFS. + +#define kRestrictR "r" +#define kRestrictRB "rb" +#define kRestrictW "w" +#define kRestrictWB "rw" +#define kRestrictRWB "rwb" + +#define kRestrictMax (5U) + +#define node_cast(PTR) reinterpret_cast<NeOS::NodePtr>(PTR) + +/** + @note Refer to first enum. +*/ +#define kFileOpsCount (4U) +#define kFileMimeGeneric "n-application-kind/all" + +/** @brief invalid position. (n-pos) */ +#define kNPos (SizeT)(-1); + +namespace NeOS +{ + enum + { + kFileWriteAll = 100, + kFileReadAll = 101, + kFileReadChunk = 102, + kFileWriteChunk = 103, + kFileIOCnt = (kFileWriteChunk - kFileWriteAll) + 1, + // file flags + kFileFlagRsrc = 104, + kFileFlagData = 105, + }; + + typedef VoidPtr NodePtr; + + /** + @brief Filesystem Mgr Interface class + @brief Used to provide common I/O for a specific filesystem. +*/ + class IFilesystemMgr + { + public: + explicit IFilesystemMgr() = default; + virtual ~IFilesystemMgr() = default; + + public: + NE_COPY_DEFAULT(IFilesystemMgr); + + public: + /// @brief Mounts a new filesystem into an active state. + /// @param interface the filesystem interface + /// @return + static bool Mount(IFilesystemMgr* interface); + + /// @brief Unmounts the active filesystem + /// @return + static IFilesystemMgr* Unmount(); + + /// @brief Getter, gets the active filesystem. + /// @return + static IFilesystemMgr* GetMounted(); + + public: + virtual NodePtr Create(_Input const Char* path) = 0; + virtual NodePtr CreateAlias(_Input const Char* path) = 0; + virtual NodePtr CreateDirectory(_Input const Char* path) = 0; + virtual NodePtr CreateSwapFile(const Char* path) = 0; + + public: + virtual bool Remove(_Input const Char* path) = 0; + + public: + virtual NodePtr Open(_Input const Char* path, _Input const Char* r) = 0; + + public: + virtual Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, _Input SizeT size) = 0; + + virtual _Output VoidPtr Read(_Input NodePtr node, + _Input Int32 flags, + _Input SizeT sz) = 0; + + virtual Void Write(_Input const Char* name, + _Input NodePtr node, + _Input VoidPtr data, + _Input Int32 flags, + _Input SizeT size) = 0; + + virtual _Output VoidPtr Read(_Input const Char* name, + _Input NodePtr node, + _Input Int32 flags, + _Input SizeT sz) = 0; + + public: + virtual bool Seek(_Input NodePtr node, _Input SizeT off) = 0; + + public: + virtual SizeT Tell(_Input NodePtr node) = 0; + virtual bool Rewind(_Input NodePtr node) = 0; + }; + +#ifdef __FSKIT_INCLUDES_NEFS__ + /** + * @brief Based of IFilesystemMgr, takes care of managing NeFS + * disks. + */ + class NeFileSystemMgr final : public IFilesystemMgr + { + public: + explicit NeFileSystemMgr(); + ~NeFileSystemMgr() override; + + public: + NE_COPY_DEFAULT(NeFileSystemMgr); + + public: + NodePtr Create(const Char* path) override; + NodePtr CreateAlias(const Char* path) override; + NodePtr CreateDirectory(const Char* path) override; + NodePtr CreateSwapFile(const Char* path) override; + + public: + bool Remove(_Input const Char* path) override; + NodePtr Open(_Input const Char* path, _Input const Char* r) override; + Void Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, _Input SizeT sz) override; + VoidPtr Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT sz) override; + bool Seek(_Input NodePtr node, _Input SizeT off) override; + SizeT Tell(_Input NodePtr node) override; + bool Rewind(_Input NodePtr node) override; + + Void Write(_Input const Char* name, + _Input NodePtr node, + _Input VoidPtr data, + _Input Int32 flags, + _Input SizeT size) override; + + _Output VoidPtr Read(_Input const Char* name, + _Input NodePtr node, + _Input Int32 flags, + _Input SizeT sz) override; + + public: + /// @brief Get NeFS parser class. + /// @return The filesystem parser class. + NeFileSystemParser* GetParser() noexcept; + + private: + NeFileSystemParser* mParser{nullptr}; + }; + +#endif // ifdef __FSKIT_INCLUDES_NEFS__ + + /** + * FileStream class. + * @tparam Encoding file encoding (char, wchar_t...) + * @tparam FSClass Filesystem contract who takes care of it. + */ + template <typename Encoding = Char, + typename FSClass = IFilesystemMgr> + class FileStream final + { + public: + explicit FileStream(const Encoding* path, const Encoding* restrict_type); + ~FileStream(); + + public: + FileStream& operator=(const FileStream&); + FileStream(const FileStream&); + + public: + ErrorOr<Int64> Write(const SizeT offset, const VoidPtr data, SizeT len) noexcept + { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictWrite && + this->fFileRestrict != kFileMgrRestrictWriteBinary) + return ErrorOr<Int64>(kErrorInvalidData); + + if (data == nullptr) + return ErrorOr<Int64>(kErrorInvalidData); + + auto man = FSClass::GetMounted(); + + if (man) + { + man->Write(offset, fFile, data, len); + return ErrorOr<Int64>(0); + } + + return ErrorOr<Int64>(kErrorInvalidData); + } + + ErrorOr<Int64> Write(const Char* name, const VoidPtr data, SizeT len) noexcept + { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictWrite && + this->fFileRestrict != kFileMgrRestrictWriteBinary) + return ErrorOr<Int64>(kErrorInvalidData); + + if (data == nullptr) + return ErrorOr<Int64>(kErrorInvalidData); + + auto man = FSClass::GetMounted(); + + if (man) + { + man->Write(name, fFile, data, 0, len); + return ErrorOr<Int64>(0); + } + + return ErrorOr<Int64>(kErrorInvalidData); + } + + VoidPtr Read(const Char* name, const SizeT sz) noexcept + { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictRead && + this->fFileRestrict != kFileMgrRestrictReadBinary) + return nullptr; + + auto man = FSClass::GetMounted(); + + if (man) + { + VoidPtr ret = man->Read(name, fFile, kFileReadAll, 0); + return ret; + } + + return nullptr; + } + + VoidPtr Read(SizeT offset, const SizeT sz) + { + if (this->fFileRestrict != kFileMgrRestrictReadWrite && + this->fFileRestrict != kFileMgrRestrictReadWriteBinary && + this->fFileRestrict != kFileMgrRestrictRead && + this->fFileRestrict != kFileMgrRestrictReadBinary) + return nullptr; + + auto man = FSClass::GetMounted(); + + if (man) + { + man->Seek(fFile, offset); + auto ret = man->Read(fFile, kFileReadChunk, sz); + + return ret; + } + + return nullptr; + } + + public: + /// @brief Leak node pointer. + /// @return The node pointer. + NodePtr Leak() + { + return fFile; + } + + /// @brief Leak MIME. + /// @return The MIME. + Char* MIME() noexcept + { + return const_cast<Char*>(fMime); + } + + enum + { + kFileMgrRestrictRead, + kFileMgrRestrictReadBinary, + kFileMgrRestrictWrite, + kFileMgrRestrictWriteBinary, + kFileMgrRestrictReadWrite, + kFileMgrRestrictReadWriteBinary, + }; + + private: + NodePtr fFile{nullptr}; + Int32 fFileRestrict{kFileMgrRestrictReadBinary}; + const Char* fMime{kFileMimeGeneric}; + }; + + using FileStreamUTF8 = FileStream<Char>; + using FileStreamUTF16 = FileStream<WideChar>; + + typedef UInt64 CursorType; + + inline static const auto kRestrictStrLen = 8U; + + /// @brief restrict information about the file descriptor. + struct FileRestrictKind final + { + Char fRestrict[kRestrictStrLen]; + Int32 fMappedTo; + }; + + /// @brief constructor + template <typename Encoding, typename Class> + inline FileStream<Encoding, Class>::FileStream(const Encoding* path, + const Encoding* restrict_type) + : fFile(Class::GetMounted()->Open(path, restrict_type)) + { + const SizeT kRestrictCount = kRestrictMax; + const FileRestrictKind kRestrictList[] = { + { + .fRestrict = kRestrictR, + .fMappedTo = kFileMgrRestrictRead, + }, + { + .fRestrict = kRestrictRB, + .fMappedTo = kFileMgrRestrictReadBinary, + }, + { + .fRestrict = kRestrictRWB, + .fMappedTo = kFileMgrRestrictReadWriteBinary, + }, + { + .fRestrict = kRestrictW, + .fMappedTo = kFileMgrRestrictWrite, + }, + { + .fRestrict = kRestrictWB, + .fMappedTo = kFileMgrRestrictReadWrite, + }}; + + for (SizeT index = 0; index < kRestrictCount; ++index) + { + if (rt_string_cmp(restrict_type, kRestrictList[index].fRestrict, + rt_string_len(kRestrictList[index].fRestrict)) == 0) + { + fFileRestrict = kRestrictList[index].fMappedTo; + break; + } + } + + kout << "new file: " << path << ".\r"; + } + + /// @brief destructor of the file stream. + template <typename Encoding, typename Class> + inline FileStream<Encoding, Class>::~FileStream() + { + mm_delete_heap(fFile); + } +} // namespace NeOS + +#endif // ifndef INC_FILEMGR_H diff --git a/dev/kernel/KernelKit/HardwareThreadScheduler.h b/dev/kernel/KernelKit/HardwareThreadScheduler.h new file mode 100644 index 00000000..1866686e --- /dev/null +++ b/dev/kernel/KernelKit/HardwareThreadScheduler.h @@ -0,0 +1,149 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef __INC_MP_MANAGER_H__ +#define __INC_MP_MANAGER_H__ + +#include <ArchKit/ArchKit.h> +#include <CompilerKit/CompilerKit.h> +#include <NewKit/Ref.h> + +/// @note Last Rev Sun 28 Jul CET 2024 +/// @note Last Rev Thu, Aug 1, 2024 9:07:38 AM + +#define kMaxAPInsideSched (8U) + +namespace NeOS +{ + class HardwareThread; + class HardwareThreadScheduler; + + using ThreadID = UInt32; + + enum ThreadKind + { + kAPInvalid, + kAPSystemReserved, // System reserved thread, well user can't use it + kAPStandard, // user thread, cannot be used by Kernel + kAPRealTime, // fallback thread, cannot be used by user if not clear or + // used by Kernel. + kAPBoot, // The core we booted from, the mama. + kAPCount, + }; + + typedef enum ThreadKind ThreadKind; + typedef ThreadID ThreadID; + + /***********************************************************************************/ + /// + /// \name HardwareThread + /// \brief Abstraction over the CPU's core, used to run processes or threads. + /// + /***********************************************************************************/ + + class HardwareThread final + { + public: + explicit HardwareThread(); + ~HardwareThread(); + + public: + NE_COPY_DEFAULT(HardwareThread) + + public: + operator bool(); + + public: + void Wake(const bool wakeup = false) noexcept; + void Busy(const bool busy = false) noexcept; + + public: + bool Switch(VoidPtr image, Ptr8 stack_ptr, HAL::StackFramePtr frame, const ThreadID& pid); + bool IsWakeup() noexcept; + + public: + HAL::StackFramePtr StackFrame() noexcept; + const ThreadKind& Kind() noexcept; + bool IsBusy() noexcept; + const ThreadID& ID() noexcept; + + private: + HAL::StackFramePtr fStack{nullptr}; + ThreadKind fKind{ThreadKind::kAPStandard}; + ThreadID fID{0}; + ThreadID fPID{0}; + Bool fWakeup{NO}; + Bool fBusy{NO}; + UInt64 fPTime{0}; + + private: + friend class HardwareThreadScheduler; + friend class UserProcessHelper; + }; + + /// + /// \name HardwareThreadScheduler + /// \brief Class to manage the thread scheduling. + /// + + class HardwareThreadScheduler final : public ISchedulable + { + private: + friend class UserProcessHelper; + + public: + explicit HardwareThreadScheduler(); + ~HardwareThreadScheduler(); + NE_COPY_DEFAULT(HardwareThreadScheduler); + + public: + HAL::StackFramePtr Leak() noexcept; + + public: + Ref<HardwareThread*> operator[](const SizeT& idx); + bool operator!() noexcept; + operator bool() noexcept; + + const Bool IsUser() override + { + return Yes; + } + + const Bool IsKernel() override + { + return No; + } + + const Bool HasMP() override + { + return kHandoverHeader->f_HardwareTables.f_MultiProcessingEnabled; + } + + public: + /// @brief Shared instance of the MP Mgr. + /// @return the reference to the mp manager class. + STATIC HardwareThreadScheduler& The(); + + public: + /// @brief Returns the amount of threads present in the system. + /// @returns SizeT the amount of cores present. + SizeT Capacity() noexcept; + + private: + Array<HardwareThread, kMaxAPInsideSched> fThreadList; + ThreadID fCurrentThread{0}; + }; + + /// @brief wakes up thread. + /// wakes up thread from hang. + Void mp_wakeup_thread(HAL::StackFramePtr stack); + + /// @brief makes thread sleep. + /// hooks and hangs thread to prevent code from executing. + Void mp_hang_thread(HAL::StackFramePtr stack); +} // namespace NeOS + +#endif // !__INC_MP_MANAGER_H__ diff --git a/dev/kernel/KernelKit/IDylibObject.h b/dev/kernel/KernelKit/IDylibObject.h new file mode 100644 index 00000000..c872b86f --- /dev/null +++ b/dev/kernel/KernelKit/IDylibObject.h @@ -0,0 +1,48 @@ +/* + * ======================================================== + * + * Kernel + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include <NewKit/Defines.h> +#include <CompilerKit/CompilerKit.h> + +#define NE_DYLIB_OBJECT : public IDylibObject + +namespace NeOS +{ + /// @brief DLL class object. A handle to a shared library. + class IDylibObject + { + public: + explicit IDylibObject() = default; + virtual ~IDylibObject() = default; + + struct DLL_TRAITS final + { + VoidPtr ImageObject{nullptr}; + VoidPtr ImageEntrypointOffset{nullptr}; + + Bool IsValid() + { + return ImageObject && ImageEntrypointOffset; + } + }; + + NE_COPY_DEFAULT(IDylibObject); + + virtual DLL_TRAITS** GetAddressOf() = 0; + virtual DLL_TRAITS* Get() = 0; + + virtual Void Mount(DLL_TRAITS* to_mount) = 0; + virtual Void Unmount() = 0; + }; + + /// @brief Pure implementation, missing method/function handler. + EXTERN_C void __zka_pure_call(void); +} // namespace NeOS diff --git a/dev/kernel/KernelKit/IPEFDylibObject.h b/dev/kernel/KernelKit/IPEFDylibObject.h new file mode 100644 index 00000000..20f87410 --- /dev/null +++ b/dev/kernel/KernelKit/IPEFDylibObject.h @@ -0,0 +1,106 @@ +/* + * ======================================================== + * + * Kernel + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#ifndef __KERNELKIT_SHARED_OBJECT_H__ +#define __KERNELKIT_SHARED_OBJECT_H__ + +#include <KernelKit/PEF.h> +#include <NewKit/Defines.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/IDylibObject.h> + +namespace NeOS +{ + /** + * @brief Shared Library class + * Load library from this class + */ + class IPEFDylibObject final NE_DYLIB_OBJECT + { + public: + explicit IPEFDylibObject() = default; + ~IPEFDylibObject() = default; + + public: + NE_COPY_DEFAULT(IPEFDylibObject); + + private: + DLL_TRAITS* fMounted{nullptr}; + + public: + DLL_TRAITS** GetAddressOf() + { + return &fMounted; + } + + DLL_TRAITS* Get() + { + return fMounted; + } + + public: + void Mount(DLL_TRAITS* to_mount) + { + if (!to_mount || !to_mount->ImageObject) + return; + + fMounted = to_mount; + + if (fLoader && to_mount) + { + delete fLoader; + fLoader = nullptr; + } + + if (!fLoader) + { + fLoader = new PEFLoader(fMounted->ImageObject); + } + } + + void Unmount() + { + if (fMounted) + fMounted = nullptr; + }; + + template <typename SymbolType> + SymbolType Load(const Char* symbol_name, SizeT len, Int32 kind) + { + if (symbol_name == nullptr || *symbol_name == 0) + return nullptr; + if (len > kPathLen || len < 1) + return nullptr; + + auto ret = + reinterpret_cast<SymbolType>(fLoader->FindSymbol(symbol_name, kind)); + + if (!ret) + { + if (kind == kPefCode) + return (VoidPtr)&__zka_pure_call; + + return nullptr; + } + + return ret; + } + + private: + PEFLoader* fLoader{nullptr}; + }; + + typedef IPEFDylibObject* IDylibRef; + + EXTERN_C IDylibRef rtl_init_dylib(UserProcess& header); + EXTERN_C Void rtl_fini_dylib(UserProcess& header, IDylibRef lib, Bool* successful); +} // namespace NeOS + +#endif /* ifndef __KERNELKIT_SHARED_OBJECT_H__ */ diff --git a/dev/kernel/KernelKit/LPC.h b/dev/kernel/KernelKit/LPC.h new file mode 100644 index 00000000..d76eeff1 --- /dev/null +++ b/dev/kernel/KernelKit/LPC.h @@ -0,0 +1,70 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +/// @file LPC.h +/// @brief Local Process Codes. + +#define err_local_ok() (NeOS::UserProcessScheduler::The().CurrentProcess().Leak().GetLocalCode() == NeOS::kErrorSuccess) +#define err_local_fail() (NeOS::UserProcessScheduler::The().CurrentProcess().Leak().GetLocalCode() != NeOS::kErrorSuccess) +#define err_local_get() (NeOS::UserProcessScheduler::The().CurrentProcess().Leak().GetLocalCode()) + +#define err_global_ok() (NeOS::kErrorLocalNumber == NeOS::kErrorSuccess) +#define err_global_fail() (NeOS::kErrorLocalNumber != NeOS::kErrorSuccess) +#define err_global_get() (NeOS::kErrorLocalNumber) + +namespace NeOS +{ + typedef Int32 HError; + + inline HError kErrorLocalNumber = 0UL; + + inline constexpr HError kErrorSuccess = 0; + inline constexpr HError kErrorExecutable = 33; + inline constexpr HError kErrorExecutableLib = 34; + inline constexpr HError kErrorFileNotFound = 35; + inline constexpr HError kErrorDirectoryNotFound = 36; + inline constexpr HError kErrorDiskReadOnly = 37; + inline constexpr HError kErrorDiskIsFull = 38; + inline constexpr HError kErrorProcessFault = 39; + inline constexpr HError kErrorSocketHangUp = 40; + inline constexpr HError kErrorThreadLocalStorage = 41; + inline constexpr HError kErrorMath = 42; + inline constexpr HError kErrorNoNetwork = 43; + inline constexpr HError kErrorHeapOutOfMemory = 44; + inline constexpr HError kErrorNoSuchDisk = 45; + inline constexpr HError kErrorFileExists = 46; + inline constexpr HError kErrorFormatFailed = 47; + inline constexpr HError kErrorNetworkTimeout = 48; + inline constexpr HError kErrorInternal = 49; + inline constexpr HError kErrorForkAlreadyExists = 50; + inline constexpr HError kErrorOutOfTeamSlot = 51; + inline constexpr HError kErrorHeapNotPresent = 52; + inline constexpr HError kErrorNoEntrypoint = 53; + inline constexpr HError kErrorDiskIsCorrupted = 54; + inline constexpr HError kErrorDisk = 55; + inline constexpr HError kErrorInvalidData = 56; + inline constexpr HError kErrorAsync = 57; + inline constexpr HError kErrorNonBlocking = 58; + inline constexpr HError kErrorIPC = 59; + inline constexpr HError kErrorSign = 60; + inline constexpr HError kErrorInvalidCreds = 61; + inline constexpr HError kErrorCDTrayBroken = 62; + inline constexpr HError kErrorUnrecoverableDisk = 63; + inline constexpr HError kErrorFileLocked = 64; + inline constexpr HError kErrorUnimplemented = -1; + + /// @brief Raises a bug check stop code. + Void err_bug_check_raise(Void) noexcept; + + /// @brief Does a system wide bug check. + /// @param void no params are needed. + /// @return if error-free: false, otherwise true. + Boolean err_bug_check(Void) noexcept; +} // namespace NeOS diff --git a/dev/kernel/KernelKit/LoaderInterface.h b/dev/kernel/KernelKit/LoaderInterface.h new file mode 100644 index 00000000..04e197aa --- /dev/null +++ b/dev/kernel/KernelKit/LoaderInterface.h @@ -0,0 +1,34 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <HintsKit/CompilerHint.h> +#include <NewKit/Defines.h> +#include <NewKit/ErrorOr.h> + +namespace NeOS +{ + /// @brief This interface is used to make loader contracts (MSCOFF, PEF). + /// @author @Amlal-El-Mahrouss + class LoaderInterface + { + public: + explicit LoaderInterface() = default; + virtual ~LoaderInterface() = default; + + NE_COPY_DEFAULT(LoaderInterface); + + public: + virtual _Output ErrorOr<VoidPtr> GetBlob() = 0; + virtual _Output const Char* AsString() = 0; + virtual _Output const Char* MIME() = 0; + virtual _Output const Char* Path() = 0; + virtual _Output ErrorOr<VoidPtr> FindStart() = 0; + virtual _Output VoidPtr FindSymbol(_Input const Char* name, _Input Int32 kind) = 0; + }; +} // namespace NeOS diff --git a/dev/kernel/KernelKit/LockDelegate.h b/dev/kernel/KernelKit/LockDelegate.h new file mode 100644 index 00000000..a657caa0 --- /dev/null +++ b/dev/kernel/KernelKit/LockDelegate.h @@ -0,0 +1,69 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Atom.h> +#include <NewKit/Defines.h> + +namespace NeOS +{ + enum + { + kLockDone = 200, + kLockTimedOut, + }; + + /// @brief Lock condition pointer. + typedef Boolean* LockPtr; + + /// @brief Locking delegate class, hangs until limit. + /// @tparam N the amount of cycles to wait. + template <SizeT N> + class LockDelegate final + { + public: + LockDelegate() = delete; + + public: + explicit LockDelegate(LockPtr expr) + { + auto spin = 0U; + + while (spin < N) + { + if (*expr) + { + fLockStatus | kLockDone; + break; + } + + ++spin; + } + + if (spin > N) + fLockStatus | kLockTimedOut; + } + + ~LockDelegate() = default; + + LockDelegate& operator=(const LockDelegate&) = delete; + LockDelegate(const LockDelegate&) = delete; + + bool Done() + { + return fLockStatus[kLockDone] == kLockDone; + } + + bool HasTimedOut() + { + return fLockStatus[kLockTimedOut] != kLockTimedOut; + } + + private: + Atom<UInt> fLockStatus; + }; +} // namespace NeOS diff --git a/dev/kernel/KernelKit/MBCI/.keep b/dev/kernel/KernelKit/MBCI/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/KernelKit/MBCI/.keep diff --git a/dev/kernel/KernelKit/MSDOS.h b/dev/kernel/KernelKit/MSDOS.h new file mode 100644 index 00000000..1a3df13b --- /dev/null +++ b/dev/kernel/KernelKit/MSDOS.h @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: MSDOS.h + Purpose: MS-DOS header for Kernel. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#ifndef __MSDOS_EXEC__ +#define __MSDOS_EXEC__ + +#include <KernelKit/PE.h> +#include <NewKit/Defines.h> + +// Last Rev +// Sat Feb 24 CET 2024 + +#define kMagMz0 'M' +#define kMagMz1 'Z' + +typedef NeOS::UInt32 DosWord; +typedef NeOS::Long DosLong; + +typedef struct _DosHeader +{ + NeOS::UInt8 eMagic[2]; + DosWord eMagLen; + DosWord ePagesCount; + DosWord eCrlc; + DosWord eCParHdr; + DosWord eMinAlloc; + DosWord eMaxAlloc; + DosWord eStackSeg; + DosWord eStackPtr; + DosWord eChksum; + DosWord eIp; + DosWord eCs; + DosWord eLfarlc; + DosWord eOvno; + DosWord eRes[4]; + DosWord eOemid; + DosWord eOeminfo; + DosWord eRes2[10]; + DosLong eLfanew; +} DosHeader, *DosHeaderPtr; + +#endif /* ifndef __MSDOS_EXEC__ */ diff --git a/dev/kernel/KernelKit/MemoryMgr.h b/dev/kernel/KernelKit/MemoryMgr.h new file mode 100644 index 00000000..93718493 --- /dev/null +++ b/dev/kernel/KernelKit/MemoryMgr.h @@ -0,0 +1,87 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef INC_KERNEL_HEAP_H +#define INC_KERNEL_HEAP_H + +/// @date 30/01/24 +/// @file: MemoryMgr.h +/// @brief: heap allocation support. + +#include <NewKit/KernelPanic.h> +#include <KernelKit/LPC.h> +#include <HintsKit/CompilerHint.h> + +namespace NeOS +{ + /// @brief Declare pointer as free. + /// @param heap_ptr the pointer. + /// @return a status code regarding the deallocation. + Int32 mm_delete_heap(VoidPtr heap_ptr); + + /// @brief Declare a new size for heap_ptr. + /// @param heap_ptr the pointer. + /// @return unsupported always returns nullptr. + VoidPtr mm_realloc_heap(VoidPtr heap_ptr, SizeT new_sz); + + /// @brief Check if pointer is a valid Kernel pointer. + /// @param heap_ptr the pointer + /// @return if it exists it returns true. + Boolean mm_is_valid_heap(VoidPtr heap_ptr); + + /// @brief Allocate chunk of memory. + /// @param sz Size of pointer + /// @param wr Read Write bit. + /// @param user User enable bit. + /// @return The newly allocated pointer, or nullptr. + VoidPtr mm_new_heap(const SizeT sz, const Bool wr, const Bool user); + + /// @brief Protect the heap with a CRC value. + /// @param heap_ptr pointer. + /// @return if it valid: point has crc now., otherwise fail. + Boolean mm_protect_heap(VoidPtr heap_ptr); + + /// @brief Makes a Kernel page. + /// @param heap_ptr the page pointer. + /// @return status code + Int32 mm_make_page(VoidPtr heap_ptr); + + /// @brief Overwrites and set the flags of a heap header. + /// @param heap_ptr the pointer to update. + /// @param flags the flags to set. + Int32 mm_make_flags(VoidPtr heap_ptr, UInt64 flags); + + /// @brief Gets the flags of a heap header. + /// @param heap_ptr the pointer to get. + UInt64 mm_get_flags(VoidPtr heap_ptr); + + /// @brief Allocate C++ class. + /// @param cls The class to allocate. + /// @param args The args to pass. + template <typename T, typename... Args> + inline BOOL mm_new_class(_Input _Output T** cls, _Input Args&&... args) + { + if (*cls) + { + err_global_get() = NeOS::kErrorInvalidData; + return NO; + } + + *cls = new T(move(args)...); + return *cls; + } + + /// @brief Delete and nullify C++ class. + /// @param cls The class to delete. + template <typename T> + inline Void mm_delete_class(_Input _Output T** cls) + { + delete *cls; + *cls = nullptr; + } +} // namespace NeOS + +#endif // !INC_KERNEL_HEAP_H diff --git a/dev/kernel/KernelKit/PCI/DMA.h b/dev/kernel/KernelKit/PCI/DMA.h new file mode 100644 index 00000000..68f3fa37 --- /dev/null +++ b/dev/kernel/KernelKit/PCI/DMA.h @@ -0,0 +1,81 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/PCI/Device.h> +#include <NewKit/Array.h> +#include <NewKit/OwnPtr.h> +#include <NewKit/Ref.h> + +namespace NeOS +{ + enum class DmaKind + { + PCI, // Bus mastering is required to be turned on. Basiaclly a request + // control system. 64-Bit access depends on the PAE bit and the device + // (if Double Address Cycle is available) + ISA, // Four DMA channels 0-3; 8 bit transfers and only a megabyte of RAM. + Invalid, + }; + + class DMAWrapper final + { + public: + explicit DMAWrapper() = delete; + + public: + explicit DMAWrapper(nullPtr) = delete; + explicit DMAWrapper(voidPtr Ptr, DmaKind Kind = DmaKind::PCI) + : fAddress(Ptr), fKind(Kind) + { + } + + public: + DMAWrapper& operator=(voidPtr Ptr); + + public: + DMAWrapper& operator=(const DMAWrapper&) = default; + DMAWrapper(const DMAWrapper&) = default; + + public: + ~DMAWrapper() = default; + + template <class T> + T* operator->(); + + template <class T> + T* Get(const UIntPtr off = 0); + + public: + operator bool(); + bool operator!(); + + public: + bool Write(const UIntPtr& bit, const UInt32& offset); + UIntPtr Read(const UInt32& offset); + Boolean Check(UIntPtr offset) const; + + public: + UIntPtr operator[](const UIntPtr& offset); + + private: + voidPtr fAddress{nullptr}; + DmaKind fKind{DmaKind::Invalid}; + + private: + friend class DMAFactory; + }; + + class DMAFactory final + { + public: + static OwnPtr<IOBuf<Char*>> Construct(OwnPtr<DMAWrapper>& dma); + }; +} // namespace NeOS + +#include <KernelKit/PCI/DMA.inl> diff --git a/dev/kernel/KernelKit/PCI/DMA.inl b/dev/kernel/KernelKit/PCI/DMA.inl new file mode 100644 index 00000000..d9c6e551 --- /dev/null +++ b/dev/kernel/KernelKit/PCI/DMA.inl @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +namespace NeOS +{ + template <class T> + T* DMAWrapper::operator->() + { + return this->fAddress; + } + + template <class T> + T* DMAWrapper::Get(const UIntPtr offset) + { + return reinterpret_cast<T*>((UIntPtr)this->fAddress + offset); + } +} // namespace NeOS diff --git a/dev/kernel/KernelKit/PCI/Database.h b/dev/kernel/KernelKit/PCI/Database.h new file mode 100644 index 00000000..cb12a731 --- /dev/null +++ b/dev/kernel/KernelKit/PCI/Database.h @@ -0,0 +1,58 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ +#pragma once + +#include <KernelKit/PCI/Device.h> +#include <NewKit/Defines.h> + +namespace NeOS +{ + namespace Types + { + // https://wiki.osdev.org/PCI + enum class PciDeviceKind : UChar + { + MassStorageController = 0x1, + NetworkController = 0x2, + DisplayController = 0x3, + MultimediaController = 0x4, + MemoryController = 0x5, + Bridge = 0x6, + CommunicationController = 0x7, + GenericSystemPeripheral = 0x8, + InputDeviceController = 0x9, + DockingStation = 0xa, + Processor = 0xb, + SerialBusController = 0xc, + WirelessController = 0xd, + IntelligentController = 0xe, + SatelliteCommunicationsController = 0xf, + CoProcessor = 0x40, + Unassgined = 0xf, + Invalid = Unassgined, + }; + } // namespace Types +} // namespace NeOS + +inline BOOL operator!=(const NeOS::Types::PciDeviceKind& lhs, NeOS::UChar rhs) +{ + return rhs != (NeOS::UChar)lhs; +} + +inline BOOL operator==(const NeOS::Types::PciDeviceKind& lhs, NeOS::UChar rhs) +{ + return rhs == (NeOS::UChar)lhs; +} + +inline BOOL operator!=(NeOS::UChar lhs, const NeOS::Types::PciDeviceKind& rhs) +{ + return lhs != (NeOS::UChar)rhs; +} + +inline BOOL operator==(NeOS::UChar lhs, const NeOS::Types::PciDeviceKind& rhs) +{ + return lhs == (NeOS::UChar)rhs; +}
\ No newline at end of file diff --git a/dev/kernel/KernelKit/PCI/Device.h b/dev/kernel/KernelKit/PCI/Device.h new file mode 100644 index 00000000..9870f618 --- /dev/null +++ b/dev/kernel/KernelKit/PCI/Device.h @@ -0,0 +1,81 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS::PCI +{ + enum class PciConfigKind : UShort + { + ConfigAddress = 0xCF8, + ConfigData = 0xCFC, + CommandReg = 0x0004, + Invalid = 0xFFFF, + }; + + class Device final + { + public: + Device() = default; + + public: + explicit Device(UShort bus, UShort device, UShort function, UInt32 bar); + + Device& operator=(const Device&) = default; + + Device(const Device&) = default; + + ~Device(); + + public: + UInt Read(UInt bar, Size szData); + void Write(UInt bar, UIntPtr data, Size szData); + + public: + operator bool(); + + public: + template <typename T> + UInt Read(UInt bar) + { + static_assert(sizeof(T) <= 4, "64-bit PCI addressing is unsupported"); + return Read(bar, sizeof(T)); + } + + template <typename T> + void Write(UInt bar, UIntPtr data) + { + static_assert(sizeof(T) <= 4, "64-bit PCI addressing is unsupported"); + Write(bar, data, sizeof(T)); + } + + public: + UShort DeviceId(); + UShort VendorId(); + UShort InterfaceId(); + UChar Class(); + UChar Subclass(); + UChar ProgIf(); + UChar HeaderType(); + UIntPtr Bar(UInt32 bar_in); + + public: + void EnableMmio(UInt32 bar_in); + void BecomeBusMaster(UInt32 bar_in); // for PCI-DMA, PC-DMA does not need that. + + UShort Vendor(); + + private: + UShort fBus; + UShort fDevice; + UShort fFunction; + UInt32 fBar; + }; +} // namespace NeOS::PCI + +EXTERN_C void NewOSPCISetCfgTarget(NeOS::UInt bar); +EXTERN_C NeOS::UInt NewOSPCIReadRaw(NeOS::UInt bar); diff --git a/dev/kernel/KernelKit/PCI/Express.h b/dev/kernel/KernelKit/PCI/Express.h new file mode 100644 index 00000000..c437a1cb --- /dev/null +++ b/dev/kernel/KernelKit/PCI/Express.h @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <KernelKit/PCI/PCI.h> + +#define PCI_EXPRESS_BUS_COUNT (4096) diff --git a/dev/kernel/KernelKit/PCI/IO.h b/dev/kernel/KernelKit/PCI/IO.h new file mode 100644 index 00000000..1d60df8e --- /dev/null +++ b/dev/kernel/KernelKit/PCI/IO.h @@ -0,0 +1,75 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <ArchKit/ArchKit.h> +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/Ref.h> + +namespace NeOS +{ + template <SizeT Sz> + class IOArray final + { + public: + IOArray() = delete; + + IOArray(nullPtr) = delete; + + explicit IOArray(Array<UShort, Sz>& ports) + : fPorts(ports) + { + } + + ~IOArray() + { + } + + IOArray& operator=(const IOArray&) = default; + + IOArray(const IOArray&) = default; + + operator bool() + { + return !fPorts.Empty(); + } + + public: + template <typename T> + T In(SizeT index); + + template <typename T> + void Out(SizeT index, T value); + + private: + Array<UShort, Sz> fPorts; + }; + + inline constexpr UInt16 kMaxPorts = 16; + + using IOArray16 = IOArray<kMaxPorts>; + + template <SizeT Sz> + inline Array<UShort, Sz> make_ports(UShort base) + { + Array<UShort, Sz> ports; + + for (UShort i = 0; i < Sz; ++i) + { + ports[i] = base + i; + } + + return ports; + } +} // namespace NeOS + +#ifdef __x86_64__ +#include <KernelKit/PCI/IOArray+AMD64.inl> +#else +#error Please provide platform specific code for the I/O +#endif // ifdef __x86_64__ diff --git a/dev/kernel/KernelKit/PCI/IOArray+AMD64.inl b/dev/kernel/KernelKit/PCI/IOArray+AMD64.inl new file mode 100644 index 00000000..2630fa98 --- /dev/null +++ b/dev/kernel/KernelKit/PCI/IOArray+AMD64.inl @@ -0,0 +1,54 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: IO-Impl-AMD64.h + Purpose: I/O for AMD64. + + Revision History: + + 30/01/24: Add file. (amlel) + 02/02/24: Update I/O routines. (amlel) + +------------------------------------------- */ + +namespace NeOS +{ + template <SizeT Sz> + template <typename T> + T IOArray<Sz>::In(SizeT index) + { + switch (sizeof(T)) + { +#ifdef __NE_AMD64__ + case 4: + return HAL::rt_in32(fPorts[index].Leak()); + case 2: + return HAL::rt_in16(fPorts[index].Leak()); + case 1: + return HAL::rt_in8(fPorts[index].Leak()); +#endif + default: + return 0xFFFF; + } + } + + template <SizeT Sz> + template <typename T> + void IOArray<Sz>::Out(SizeT index, T value) + { + switch (sizeof(T)) + { +#ifdef __NE_AMD64__ + case 4: + HAL::rt_out32(fPorts[index].Leak(), value); + case 2: + HAL::rt_out16(fPorts[index].Leak(), value); + case 1: + HAL::rt_out8(fPorts[index].Leak(), value); +#endif + default: + break; + } + } +} // namespace NeOS
\ No newline at end of file diff --git a/dev/kernel/KernelKit/PCI/Iterator.h b/dev/kernel/KernelKit/PCI/Iterator.h new file mode 100644 index 00000000..2a788450 --- /dev/null +++ b/dev/kernel/KernelKit/PCI/Iterator.h @@ -0,0 +1,43 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef __PCI_ITERATOR_H__ +#define __PCI_ITERATOR_H__ + +#include <KernelKit/PCI/Database.h> +#include <KernelKit/PCI/Device.h> +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/Ref.h> + +#define NE_BUS_COUNT (256) +#define NE_DEVICE_COUNT (33) +#define NE_FUNCTION_COUNT (8) + +namespace NeOS::PCI +{ + class Iterator final + { + public: + Iterator() = delete; + + public: + explicit Iterator(const Types::PciDeviceKind& deviceType); + + Iterator& operator=(const Iterator&) = default; + Iterator(const Iterator&) = default; + + ~Iterator(); + + public: + Ref<PCI::Device> operator[](const Size& sz); + + private: + Array<PCI::Device, NE_BUS_COUNT> fDevices; + }; +} // namespace NeOS::PCI + +#endif // __PCI_ITERATOR_H__ diff --git a/dev/kernel/KernelKit/PCI/PCI.h b/dev/kernel/KernelKit/PCI/PCI.h new file mode 100644 index 00000000..7eec9ec1 --- /dev/null +++ b/dev/kernel/KernelKit/PCI/PCI.h @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +#define kPCIConfigAddressPort (0xCF8) +#define kPCIConfigDataPort (0xCFC) + +#define kPCIDeviceCount (32) +#define kPCIFuncCount (8) +#define kPCIBusCount (256U) + +namespace NeOS::PCI +{ + // model + struct DeviceHeader + { + UInt16 VendorId; + UInt16 DeviceId; + UInt8 Command; + UInt8 Status; + UInt8 RevisionId; + UInt8 ProgIf; + UInt8 SubClass; + UInt8 Class; + UInt8 CacheLineSz; + UInt8 LatencyTimer; + UInt8 HeaderType; + UInt8 Bist; + UInt8 Bus; + UInt8 Device; + UInt8 Function; + }; + + namespace Detail + { + class BAR + { + public: + UIntPtr BAR; + SizeT Size; + }; + } // namespace Detail + + class BAR + { + public: + Detail::BAR BAR1; + Detail::BAR BAR2; + Detail::BAR BAR3; + Detail::BAR BAR4; + Detail::BAR BAR5; + }; +} // namespace NeOS::PCI diff --git a/dev/kernel/KernelKit/PE.h b/dev/kernel/KernelKit/PE.h new file mode 100644 index 00000000..dbcf2ded --- /dev/null +++ b/dev/kernel/KernelKit/PE.h @@ -0,0 +1,143 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: PE.h + Purpose: Portable Executable for Kernel. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#ifndef __KERNELKIT_INC_PE_H__ +#define __KERNELKIT_INC_PE_H__ + +#include <NewKit/Defines.h> + +#define kPeSignature 0x00004550 + +#define kPeDLLBase 0x4000000 +#define kPeEXEBase 0x1000000 + +#define kPeMagic32 0x010b +#define kPeMagic64 0x020b + +#define kPeMachineAMD64 0x8664 +#define kPeMachineARM64 0xaa64 + +typedef struct LDR_EXEC_HEADER final +{ + NeOS::UInt32 Signature; + NeOS::UInt16 Machine; + NeOS::UInt16 NumberOfSections; + NeOS::UInt32 TimeDateStamp; + NeOS::UInt32 PointerToSymbolTable; + NeOS::UInt32 NumberOfSymbols; + NeOS::UInt16 SizeOfOptionalHeader; + NeOS::UInt16 Characteristics; +} LDR_EXEC_HEADER, *LDR_EXEC_HEADER_PTR; + +typedef struct LDR_OPTIONAL_HEADER final +{ + NeOS::UInt16 Magic; // 0x010b - PE32, 0x020b - PE32+ (64 bit) + NeOS::UInt8 MajorLinkerVersion; + NeOS::UInt8 MinorLinkerVersion; + NeOS::UInt32 SizeOfCode; + NeOS::UInt32 SizeOfInitializedData; + NeOS::UInt32 SizeOfUninitializedData; + NeOS::UInt32 AddressOfEntryPoint; + NeOS::UInt32 BaseOfCode; + NeOS::UInt32 BaseOfData; + NeOS::UInt32 ImageBase; + NeOS::UInt32 SectionAlignment; + NeOS::UInt32 FileAlignment; + NeOS::UInt16 MajorOperatingSystemVersion; + NeOS::UInt16 MinorOperatingSystemVersion; + NeOS::UInt16 MajorImageVersion; + NeOS::UInt16 MinorImageVersion; + NeOS::UInt16 MajorSubsystemVersion; + NeOS::UInt16 MinorSubsystemVersion; + NeOS::UInt32 Win32VersionValue; + NeOS::UInt32 SizeOfImage; + NeOS::UInt32 SizeOfHeaders; + NeOS::UInt32 CheckSum; + NeOS::UInt16 Subsystem; + NeOS::UInt16 DllCharacteristics; + NeOS::UInt32 SizeOfStackReserve; + NeOS::UInt32 SizeOfStackCommit; + NeOS::UInt32 SizeOfHeapReserve; + NeOS::UInt32 SizeOfHeapCommit; + NeOS::UInt32 LoaderFlags; + NeOS::UInt32 NumberOfRvaAndSizes; +} LDR_OPTIONAL_HEADER, *LDR_OPTIONAL_HEADER_PTR; + +typedef struct LDR_SECTION_HEADER final +{ + NeOS::Char Name[8]; + NeOS::UInt32 VirtualSize; + NeOS::UInt32 VirtualAddress; + NeOS::UInt32 SizeOfRawData; + NeOS::UInt32 PointerToRawData; + NeOS::UInt32 PointerToRelocations; + NeOS::UInt32 PointerToLineNumbers; + NeOS::UInt16 NumberOfRelocations; + NeOS::UInt16 NumberOfLinenumbers; + NeOS::UInt32 Characteristics; +} LDR_SECTION_HEADER, *LDR_SECTION_HEADER_PTR; + +enum kExecDataDirParams +{ + kExecExport, + kExecImport, + kExecInvalid, + kExecCount, +}; + +typedef struct LDR_EXPORT_DIRECTORY +{ + NeOS::UInt32 Characteristics; + NeOS::UInt32 TimeDateStamp; + NeOS::UInt16 MajorVersion; + NeOS::UInt16 MinorVersion; + NeOS::UInt32 Name; + NeOS::UInt32 Base; + NeOS::UInt32 NumberOfFunctions; + NeOS::UInt32 NumberOfNames; + NeOS::UInt32 AddressOfFunctions; // export table rva + NeOS::UInt32 AddressOfNames; + NeOS::UInt32 AddressOfNameOrdinal; // ordinal table rva +} LDR_EXPORT_DIRECTORY, *LDR_EXPORT_DIRECTORY_PTR; + +typedef struct LDR_IMPORT_DIRECTORY +{ + union { + NeOS::UInt32 Characteristics; + NeOS::UInt32 OriginalFirstThunk; + }; + NeOS::UInt32 TimeDateStamp; + NeOS::UInt32 ForwarderChain; + NeOS::UInt32 NameRva; + NeOS::UInt32 ThunkTableRva; +} LDR_IMPORT_DIRECTORY, *LDR_IMPORT_DIRECTORY_PTR; + +typedef struct LDR_DATA_DIRECTORY +{ + NeOS::UInt32 VirtualAddress; + NeOS::UInt32 Size; +} LDR_DATA_DIRECTORY, *LDR_DATA_DIRECTORY_PTR; + +typedef struct LDR_IMAGE_HEADER +{ + LDR_EXEC_HEADER Header; + LDR_OPTIONAL_HEADER OptHdr; +} LDR_IMAGE_HEADER, *LDR_IMAGE_HEADER_PTR; + +enum +{ + kUserSection = 0x00000020, + kPEResourceId = 0xFFaadd00, +}; + +#endif /* ifndef __KERNELKIT_INC_PE_H__ */ diff --git a/dev/kernel/KernelKit/PECodeMgr.h b/dev/kernel/KernelKit/PECodeMgr.h new file mode 100644 index 00000000..1e445b9f --- /dev/null +++ b/dev/kernel/KernelKit/PECodeMgr.h @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: PECodeMgr.h + Purpose: PE32+ Code Mgr and DLL mgr. + + Revision History: + + 12/02/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +//////////////////////////////////////////////////// + +// LAST REV: Mon Feb 12 13:52:01 CET 2024 + +//////////////////////////////////////////////////// + +#include <KernelKit/PE.h> +#include <NewKit/ErrorOr.h> +#include <NewKit/KString.h> diff --git a/dev/kernel/KernelKit/PEF.h b/dev/kernel/KernelKit/PEF.h new file mode 100644 index 00000000..dfdaed12 --- /dev/null +++ b/dev/kernel/KernelKit/PEF.h @@ -0,0 +1,117 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: PEF.h + Purpose: Preferred Executable Format for Kernel. + + Revision History: + + ?/?/23: Added file (amlel) + +------------------------------------------- */ + +#ifndef KERNELKIT_PEF_H +#define KERNELKIT_PEF_H + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/LoaderInterface.h> +#include <NewKit/Defines.h> + +#define kPefMagic "Joy!" +#define kPefMagicFat "yoJ!" + +#define kPefMagicLen 5 + +#define kPefVersion 3 +#define kPefNameLen 256U + +/* not mandatory, only for non fork based filesystems. */ +#define kPefExt ".o" +#define kPefDylibExt ".dylib" +#define kPefLibExt ".lib" +#define kPefObjectExt ".obj" +#define kPefDebugExt ".dbg" +#define kPefDriverExt ".sys" + +// Kernel System Binary Interface. +#define kPefAbi (0x5046) + +#define kPefBaseOrigin (0x40000000) + +#define kPefStart "__ImageStart" + +#define kPefForkKind kPefMagic +#define kPefForkKindFAT kPefMagicFat + +namespace NeOS +{ + enum + { + kPefArchIntel86S, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64x0, /* 64x0. ISA */ + kPefArch32x0, /* 32x0. ISA */ + kPefArchPowerPC, + kPefArchARM64, + kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, + }; + + enum + { + kPefSubArchAMD, + kPefSubArchIntel, + kPefSubArchARM, + kPefSubArchGeneric, + kPefSubArchIBM, + }; + + enum + { + kPefKindExec = 1, /* .o */ + kPefKindDylib = 2, /* .dylib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, + }; + + typedef struct PEFContainer final + { + Char Magic[kPefMagicLen]; + UInt32 Linker; + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; + SizeT HdrSz; /* Size of header */ + SizeT Count; /* container header count */ + } PACKED PEFContainer; + + /* First PEFCommandHeader starts after PEFContainer */ + + typedef struct PEFCommandHeader final + { + Char Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* content offset */ + SizeT Size; /* content Size */ + } PACKED PEFCommandHeader; + + enum + { + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + }; +} // namespace NeOS + +#endif /* ifndef KERNELKIT_PEF_H */ diff --git a/dev/kernel/KernelKit/PEFCodeMgr.h b/dev/kernel/KernelKit/PEFCodeMgr.h new file mode 100644 index 00000000..47aea432 --- /dev/null +++ b/dev/kernel/KernelKit/PEFCodeMgr.h @@ -0,0 +1,72 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef _INC_CODE_MANAGER_PEF_H_ +#define _INC_CODE_MANAGER_PEF_H_ + +#include <KernelKit/PEF.h> +#include <NewKit/ErrorOr.h> +#include <NewKit/KString.h> +#include <KernelKit/FileMgr.h> + +#ifndef INC_PROCESS_SCHEDULER_H +#include <KernelKit/UserProcessScheduler.h> +#endif + +#define kPefApplicationMime "application/vnd-zka-executable" + +namespace NeOS +{ + /// + /// \name PEFLoader + /// \brief PEF loader class. + /// + class PEFLoader : public LoaderInterface + { + private: + explicit PEFLoader() = delete; + + public: + explicit PEFLoader(const VoidPtr blob); + explicit PEFLoader(const Char* path); + ~PEFLoader() override; + + public: + NE_COPY_DEFAULT(PEFLoader); + + public: + const Char* Path() override; + const Char* AsString() override; + const Char* MIME() override; + + public: + ErrorOr<VoidPtr> FindStart() override; + VoidPtr FindSymbol(const Char* name, Int32 kind) override; + ErrorOr<VoidPtr> GetBlob() override; + + public: + bool IsLoaded() noexcept; + + private: +#ifdef __FSKIT_INCLUDES_NEFS__ + OwnPtr<FileStream<Char, NeFileSystemMgr>> fFile; +#else + OwnPtr<FileStream<Char>> fFile; +#endif // __FSKIT_INCLUDES_NEFS__ + + Ref<KString> fPath; + VoidPtr fCachedBlob; + bool fFatBinary; + bool fBad; + }; + + namespace Utils + { + ProcessID rtl_create_process(PEFLoader& exec, const Int32& procKind) noexcept; + } // namespace Utils +} // namespace NeOS + +#endif // ifndef _INC_CODE_MANAGER_PEF_H_ diff --git a/dev/kernel/KernelKit/Semaphore.h b/dev/kernel/KernelKit/Semaphore.h new file mode 100644 index 00000000..ac810c62 --- /dev/null +++ b/dev/kernel/KernelKit/Semaphore.h @@ -0,0 +1,16 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <KernelKit/Timer.h> +#include <CompilerKit/CompilerKit.h> + +namespace NeOS +{ + typedef Int64 Semaphore; +} // namespace NeOS
\ No newline at end of file diff --git a/dev/kernel/KernelKit/ThreadLocalStorage.h b/dev/kernel/KernelKit/ThreadLocalStorage.h new file mode 100644 index 00000000..573b40b8 --- /dev/null +++ b/dev/kernel/KernelKit/ThreadLocalStorage.h @@ -0,0 +1,69 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef KERNELKIT_TLS_H +#define KERNELKIT_TLS_H + +#include <NewKit/Defines.h> +#include <NewKit/ErrorOr.h> + +///! @brief Thread Local Storage for neoskrnl. + +#define kCookieMag0Idx 0 +#define kCookieMag1Idx 1 +#define kCookieMag2Idx 2 + +#define kCookieMag0 'Z' +#define kCookieMag1 'K' +#define kCookieMag2 'A' + +#define kTLSCookieLen (3U) + +struct THREAD_INFORMATION_BLOCK; + +/// @brief Thread Information Block. +/// Located in GS on AMD64, other architectures have their own stuff. (64x0, 32x0, ARM64) +struct PACKED THREAD_INFORMATION_BLOCK final +{ + NeOS::Char Cookie[kTLSCookieLen]{0}; //! Thread magic number. + NeOS::VoidPtr Record{nullptr}; //! Thread information record. +}; + +///! @brief Cookie Sanity check. +NeOS::Boolean tls_check_tib(THREAD_INFORMATION_BLOCK* the_tib); + +///! @brief new ptr syscall. +template <typename T> +T* tls_new_ptr(void) noexcept; + +///! @brief delete ptr syscall. +template <typename T> +NeOS::Boolean tls_delete_ptr(T* ptr) noexcept; + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline NeOS::Bool tls_delete_ptr(NeOS::ErrorOr<T> obj) noexcept; + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline NeOS::Bool tls_delete_ptr(NeOS::ErrorOr<T*> obj) noexcept; + +template <typename T, typename... Args> +T* tls_new_class(Args&&... args); + +/// @brief TLS install TIB and PIB. (syscall) +EXTERN_C NeOS::Void rt_install_tib(THREAD_INFORMATION_BLOCK* TIB, THREAD_INFORMATION_BLOCK* PIB); + +/// @brief TLS check (syscall) +EXTERN_C NeOS::Bool tls_check_syscall_impl(NeOS::VoidPtr TIB) noexcept; + +#include <KernelKit/ThreadLocalStorage.inl> + +// last rev 7/7/24 + +#endif /* ifndef KERNELKIT_TLS_H */ diff --git a/dev/kernel/KernelKit/ThreadLocalStorage.inl b/dev/kernel/KernelKit/ThreadLocalStorage.inl new file mode 100644 index 00000000..d912f5aa --- /dev/null +++ b/dev/kernel/KernelKit/ThreadLocalStorage.inl @@ -0,0 +1,99 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +//! @file ThreadLocalStorage.inl +//! @brief Allocate resources from the process's heap storage. + +#ifndef INC_PROCESS_SCHEDULER_H +#include <KernelKit/UserProcessScheduler.h> +#endif + +template <typename T> +inline T* tls_new_ptr(void) noexcept +{ + using namespace NeOS; + + auto ref_process = UserProcessScheduler::The().CurrentProcess(); + MUST_PASS(ref_process); + + auto pointer = ref_process.Leak().New(sizeof(T)); + + if (pointer.Error()) + return nullptr; + + return reinterpret_cast<T*>(pointer.Leak().Leak()); +} + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline NeOS::Bool tls_delete_ptr(T* obj) noexcept +{ + using namespace NeOS; + + if (!obj) + return No; + + auto ref_process = UserProcessScheduler::The().CurrentProcess(); + MUST_PASS(ref_process); + + ErrorOr<T*> obj_wrapped{obj}; + + return ref_process.Leak().Delete(obj_wrapped, sizeof(T)); +} + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline NeOS::Bool tls_delete_ptr(NeOS::ErrorOr<T> obj) noexcept +{ + return tls_delete_ptr(obj.Leak()); +} + +//! @brief Delete process pointer. +//! @param obj The pointer to delete. +template <typename T> +inline NeOS::Bool tls_delete_ptr(NeOS::ErrorOr<T*> obj) noexcept +{ + return tls_delete_ptr(obj->Leak()); +} + +/// @brief Allocate a C++ class, and then call the constructor of it. +/// @tparam T class type. +/// @tparam ...Args varg class type. +/// @param args arguments list. +/// @return Class instance. +template <typename T, typename... Args> +T* tls_new_class(Args&&... args) +{ + using namespace NeOS; + + T* obj = tls_new_ptr<T>(); + + if (obj) + { + *obj = T(forward(args)...); + return obj; + } + + return nullptr; +} + +/// @brief Delete a C++ class (call constructor first.) +/// @tparam T +/// @param obj +/// @return +template <typename T> +inline NeOS::Bool tls_delete_class(T* obj) +{ + using namespace NeOS; + + if (!obj) + return No; + + obj->~T(); + return tls_delete_ptr(obj); +} diff --git a/dev/kernel/KernelKit/Timer.h b/dev/kernel/KernelKit/Timer.h new file mode 100644 index 00000000..abca5352 --- /dev/null +++ b/dev/kernel/KernelKit/Timer.h @@ -0,0 +1,83 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <ArchKit/ArchKit.h> +#include <KernelKit/LPC.h> + +namespace NeOS +{ + class SoftwareTimer; + class TimerInterface; + + inline constexpr Int16 kTimeUnit = 1000; + + class TimerInterface + { + public: + /// @brief Default constructor + explicit TimerInterface() = default; + virtual ~TimerInterface() = default; + + public: + NE_COPY_DEFAULT(TimerInterface); + + public: + virtual BOOL Wait() noexcept; + }; + + class SoftwareTimer final : public TimerInterface + { + public: + explicit SoftwareTimer(Int64 seconds); + ~SoftwareTimer() override; + + public: + NE_COPY_DEFAULT(SoftwareTimer); + + public: + BOOL Wait() noexcept override; + + private: + IntPtr* fDigitalTimer{nullptr}; + Int64 fWaitFor{0}; + }; + + class HardwareTimer final : public TimerInterface + { + public: + explicit HardwareTimer(Int64 seconds); + ~HardwareTimer() override; + + public: + NE_COPY_DEFAULT(HardwareTimer); + + public: + BOOL Wait() noexcept override; + + private: + IntPtr* fDigitalTimer{nullptr}; + Int64 fWaitFor{0}; + }; + + inline Int64 rtl_ms(Int64 time) + { + if (time < 0) + return 0; + + // TODO: nanoseconds maybe? + return kTimeUnit * kTimeUnit * time; + } + + inline Int64 rtl_seconds(Int64 time) + { + if (time < 0) + return 0; + + return kTimeUnit * rtl_ms(time); + } +} // namespace NeOS diff --git a/dev/kernel/KernelKit/User.h b/dev/kernel/KernelKit/User.h new file mode 100644 index 00000000..9ab2b02e --- /dev/null +++ b/dev/kernel/KernelKit/User.h @@ -0,0 +1,95 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef INC_USER_H +#define INC_USER_H + +/* ------------------------------------------- + + Revision History: + + 04/03/25: Set users directory as /user/ instead of /usr/ + + ------------------------------------------- */ + +#include <CompilerKit/CompilerKit.h> +#include <KernelKit/LPC.h> +#include <NewKit/KString.h> +#include <NewKit/Defines.h> + +///! We got the Super, Standard (%s format) and Guest user, +///! all are used to make authorization operations on the OS. +#define kSuperUser "OS AUTHORITY/SUPER/%s" +#define kGuestUser "OS AUTHORITY/GUEST/%s" +#define kStdUser "OS AUTHORITY/STD/%s" + +#define kUsersDir "/user/" + +#define kMaxUserNameLen (256U) +#define kMaxUserTokenLen (256U) + +namespace NeOS +{ + class User; + + enum class UserRingKind + { + kRingInvalid = 0, + kRingStdUser = 1, + kRingSuperUser = 2, + kRingGuestUser = 5, + kRingCount = 3, + }; + + typedef Char* UserPublicKey; + typedef Char UserPublicKeyType; + + /// @brief User class. + class User final + { + public: + User() = delete; + + User(const Int32& sel, const Char* username); + User(const UserRingKind& kind, const Char* username); + + ~User(); + + public: + NE_COPY_DEFAULT(User); + + public: + bool operator==(const User& lhs); + bool operator!=(const User& lhs); + + public: + /// @brief Get software ring + const UserRingKind& Ring() noexcept; + + /// @brief Get user name + Char* Name() noexcept; + + /// @brief Is he a standard user? + Bool IsStdUser() noexcept; + + /// @brief Is she a super user? + Bool IsSuperUser() noexcept; + + /// @brief Saves a password from the public key. + Bool Save(const UserPublicKey password) noexcept; + + /// @brief Checks if a password matches the **password**. + /// @param password the password to check. + Bool Matches(const UserPublicKey password) noexcept; + + private: + UserRingKind mUserRing{UserRingKind::kRingStdUser}; + Char mUserName[kMaxUserNameLen] = {0}; + Char mUserKey[kMaxUserTokenLen] = {0}; + }; +} // namespace NeOS + +#endif /* ifndef INC_USER_H */ diff --git a/dev/kernel/KernelKit/UserProcessScheduler.h b/dev/kernel/KernelKit/UserProcessScheduler.h new file mode 100644 index 00000000..10a08e0f --- /dev/null +++ b/dev/kernel/KernelKit/UserProcessScheduler.h @@ -0,0 +1,343 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef INC_PROCESS_SCHEDULER_H +#define INC_PROCESS_SCHEDULER_H + +#include <ArchKit/ArchKit.h> +#include <KernelKit/LockDelegate.h> +#include <KernelKit/User.h> +#include <NewKit/MutableArray.h> + +#define kSchedMinMicroTime (AffinityKind::kStandard) +#define kSchedInvalidPID (-1) +#define kSchedProcessLimitPerTeam (32U) + +#define kSchedMaxMemoryLimit gib_cast(128) /* max physical memory limit */ +#define kSchedMaxStackSz mib_cast(8) /* maximum stack size */ + +#define kProcessInvalidID (-1) +#define kProcessNameLen (128U) + +//////////////////////////////////////////////////// +// The current date is: Thu 11/28/2024 // +//////////////////////////////////////////////////// + +namespace NeOS +{ + //! @note Forward class declarations. + + class IDylibObject; + class UserProcess; + class UserProcessTeam; + class UserProcessScheduler; + class UserProcessHelper; + + typedef UInt64 PTime; + + //! @brief Local Process identifier. + typedef Int64 ProcessID; + + //! @brief Local Process status enum. + enum class ProcessStatusKind : Int32 + { + kInvalid, + kStarting, + kRunning, + kKilled, + kFrozen, + kFinished, + kCount, + }; + + //! @brief Affinity is the amount of nano-seconds this process is going + //! to run. + enum class AffinityKind : Int32 + { + kRealTime = 500, + kVeryHigh = 250, + kHigh = 200, + kStandard = 1000, + kLowUsage = 1500, + kVeryLowUsage = 2000, + }; + + // operator overloading. + + inline bool operator<(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast<Int>(lhs); + Int32 rhs_int = static_cast<Int>(rhs); + + return lhs_int < rhs_int; + } + + inline bool operator>(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast<Int>(lhs); + Int32 rhs_int = static_cast<Int>(rhs); + + return lhs_int > rhs_int; + } + + inline bool operator<=(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast<Int>(lhs); + Int32 rhs_int = static_cast<Int>(rhs); + + return lhs_int <= rhs_int; + } + + inline bool operator>=(AffinityKind lhs, AffinityKind rhs) + { + Int32 lhs_int = static_cast<Int>(lhs); + Int32 rhs_int = static_cast<Int>(rhs); + + return lhs_int >= rhs_int; + } + + // end of operator overloading. + + enum class ProcessSubsystem : Int32 + { + kProcessSubsystemSecurity = 100, + kProcessSubsystemApplication, + kProcessSubsystemService, + kProcessSubsystemDriver, + kProcessSubsystemInvalid = 256U, + kProcessSubsystemCount = 4, + }; + + using ProcessTime = UInt64; + using PID = Int64; + + // for permission manager, tells where we run the code. + enum class ProcessLevelRing : Int32 + { + kRingStdUser = 1, + kRingSuperUser = 2, + kRingGuestUser = 5, + kRingCount = 5, + }; + + /// @brief Helper type to describe a code image. + using ImagePtr = VoidPtr; + + struct UserProcessImage final + { + explicit UserProcessImage() = default; + + ImagePtr fCode; + ImagePtr fBlob; + + Bool HasCode() + { + return this->fCode != nullptr; + } + + Bool HasImage() + { + return this->fBlob != nullptr; + } + }; + + /// @name UserProcess + /// @brief User process class, holds information about the running process/thread. + class UserProcess final + { + public: + explicit UserProcess(); + ~UserProcess(); + + public: + NE_COPY_DEFAULT(UserProcess); + + public: + Char Name[kProcessNameLen] = {"Process"}; + ProcessSubsystem SubSystem{ProcessSubsystem::kProcessSubsystemInvalid}; + User* Owner{nullptr}; + HAL::StackFramePtr StackFrame{nullptr}; + AffinityKind Affinity{AffinityKind::kStandard}; + ProcessStatusKind Status{ProcessStatusKind::kFinished}; + UInt8* StackReserve{nullptr}; + UserProcessImage Image{}; + SizeT StackSize{kSchedMaxStackSz}; + IDylibObject* DylibDelegate{nullptr}; + SizeT MemoryCursor{0UL}; + SizeT MemoryLimit{kSchedMaxMemoryLimit}; + SizeT UsedMemory{0UL}; + + struct ProcessMemoryHeapList final + { + VoidPtr MemoryEntry{nullptr}; + SizeT MemoryEntrySize{0UL}; + SizeT MemoryEntryPad{0UL}; + + struct ProcessMemoryHeapList* MemoryPrev{nullptr}; + struct ProcessMemoryHeapList* MemoryNext{nullptr}; + }; + + struct UserProcessSignal final + { + UIntPtr SignalArg; + ProcessStatusKind PreviousStatus; + UIntPtr SignalID; + }; + + UserProcessSignal ProcessSignal; + ProcessMemoryHeapList* ProcessMemoryHeap{nullptr}; + UserProcessTeam* ProcessParentTeam; + + VoidPtr VMRegister{0UL}; + + enum + { + kInvalidExecutableKind, + kExectuableKind, + kExectuableDylibKind, + kExectuableKindCount, + }; + + ProcessTime PTime{0}; //! @brief Process allocated tine. + + PID ProcessId{kSchedInvalidPID}; + Int32 Kind{kExectuableKind}; + + public: + //! @brief boolean operator, check status. + operator bool(); + + ///! @brief Crashes the app, exits with code ~0. + Void Crash(); + + ///! @brief Exits the app. + Void Exit(const Int32& exit_code = 0); + + ///! @brief TLS allocate. + ///! @param sz size of new ptr. + ErrorOr<VoidPtr> New(const SizeT& sz, const SizeT& pad_amount = 0); + + ///! @brief TLS free. + ///! @param ptr the pointer to free. + ///! @param sz the size of it. + template <typename T> + Boolean Delete(ErrorOr<T*> ptr, const SizeT& sz); + + ///! @brief Wakes up threads. + Void Wake(const Bool wakeup = false); + + public: + //! @brief Gets the local exit code. + const UInt32& GetExitCode() noexcept; + + ///! @brief Get the process's name + ///! @example 'C Runtime Library' + const Char* GetName() noexcept; + + //! @brief return local error code of process. + //! @return Int32 local error code. + Int32& GetLocalCode() noexcept; + + const User* GetOwner() noexcept; + const ProcessStatusKind& GetStatus() noexcept; + const AffinityKind& GetAffinity() noexcept; + + private: + UInt32 fLastExitCode{0}; + Int32 fLocalCode{0}; + + friend UserProcessScheduler; + friend UserProcessHelper; + }; + + /// \brief Processs Team (contains multiple processes inside it.) + /// Equivalent to a process batch + class UserProcessTeam final + { + public: + explicit UserProcessTeam(); + ~UserProcessTeam() = default; + + NE_COPY_DEFAULT(UserProcessTeam); + + Array<UserProcess, kSchedProcessLimitPerTeam>& AsArray(); + Ref<UserProcess>& AsRef(); + ProcessID& Id() noexcept; + + public: + Array<UserProcess, kSchedProcessLimitPerTeam> mProcessList; + Ref<UserProcess> mCurrentProcess; + ProcessID mTeamId{0}; + ProcessID mProcessCount{0}; + }; + + typedef Array<UserProcess, kSchedProcessLimitPerTeam> UserThreadArray; + + using UserProcessRef = UserProcess&; + + /// @brief Process scheduler class. + /// The main class which you call to schedule user processes. + class UserProcessScheduler final : public ISchedulable + { + friend class UserProcessHelper; + + public: + explicit UserProcessScheduler() = default; + ~UserProcessScheduler() override = default; + + NE_COPY_DEFAULT(UserProcessScheduler) + + operator bool(); + bool operator!(); + + public: + UserProcessTeam& CurrentTeam(); + + public: + ProcessID Spawn(const Char* name, VoidPtr code, VoidPtr image); + const Bool Remove(ProcessID process_id); + + const Bool IsUser() override; + const Bool IsKernel() override; + const Bool HasMP() override; + + public: + Ref<UserProcess>& CurrentProcess(); + const SizeT Run() noexcept; + + public: + STATIC UserProcessScheduler& The(); + + private: + UserProcessTeam mTeam{}; + }; + + /* + * \brief UserProcess helper class, which contains needed utilities for the scheduler. + */ + + class UserProcessHelper final + { + public: + STATIC Bool Switch(VoidPtr image_ptr, UInt8* stack_ptr, HAL::StackFramePtr frame_ptr, const PID& new_pid); + STATIC Bool CanBeScheduled(const UserProcess& process); + STATIC ErrorOr<PID> TheCurrentPID(); + STATIC SizeT StartScheduling(); + }; + + const UInt32& sched_get_exit_code(void) noexcept; +} // namespace NeOS + +#include <KernelKit/ThreadLocalStorage.h> +#include <KernelKit/UserProcessScheduler.inl> + +//////////////////////////////////////////////////// + +// END + +//////////////////////////////////////////////////// + +#endif /* ifndef INC_PROCESS_SCHEDULER_H */ diff --git a/dev/kernel/KernelKit/UserProcessScheduler.inl b/dev/kernel/KernelKit/UserProcessScheduler.inl new file mode 100644 index 00000000..6b3b9300 --- /dev/null +++ b/dev/kernel/KernelKit/UserProcessScheduler.inl @@ -0,0 +1,62 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + FILE: UserProcessScheduler.inl + PURPOSE: Low level/Ring-3 Process scheduler. + +------------------------------------------- */ + +namespace NeOS +{ + /***********************************************************************************/ + /** @brief Free pointer from usage. */ + /***********************************************************************************/ + + template <typename T> + Boolean UserProcess::Delete(ErrorOr<T*> ptr, const SizeT& sz) + { + if (!ptr) + return No; + + if (!this->ProcessMemoryHeap) + { + kout << "Process Memory is empty.\r"; + return No; + } + + ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; + + while (entry != nullptr) + { + if (entry->MemoryEntry == ptr.Leak().Leak()) + { + this->UsedMemory -= entry->MemoryEntrySize; + +#ifdef __NE_AMD64__ + auto pd = hal_read_cr3(); + + hal_write_cr3(this->VMRegister); + + auto ret = mm_delete_heap(entry->MemoryEntry); + + hal_write_cr3(pd); + + return ret == kErrorSuccess; +#else + Bool ret = mm_delete_heap(ptr.Leak().Leak()); + + return ret == kErrorSuccess; +#endif + } + + entry = entry->MemoryNext; + } + + kout << "Invalid Pointer: Trying to free a pointer which doesn't exist.\r"; + + this->Crash(); + + return No; + } +} // namespace NeOS diff --git a/dev/kernel/KernelKit/XCOFF.h b/dev/kernel/KernelKit/XCOFF.h new file mode 100644 index 00000000..5e59e717 --- /dev/null +++ b/dev/kernel/KernelKit/XCOFF.h @@ -0,0 +1,51 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: XCOFF.h + Purpose: XCOFF for Kernel. + + Revision History: + + 04/07/24: Added file (amlel) + +------------------------------------------- */ + +#ifndef INC_XOCFF_H +#define INC_XOCFF_H + +#include <NewKit/Defines.h> + +#define kXCOFF64Magic (0x01F7) + +#define kXCOFFRelFlg (0x0001) +#define kXCOFFExecutable (0x0002) +#define kXCOFFLnno (0x0004) +#define kXCOFFLSyms (0x0008) + +struct XCoffFileHeader; +struct XCoffForkHeader; + +/// @brief XCoff file header, meant for POWER apps. +typedef struct XCoffFileHeader +{ + NeOS::UInt16 fMagic; + NeOS::UInt16 fTarget; + NeOS::UInt16 fNumSecs; + NeOS::UInt32 fTimeDat; + NeOS::UIntPtr fSymPtr; + NeOS::UInt32 fNumSyms; + NeOS::UInt16 fOptHdr; // ?: Number of bytes in optional header +} XCoffFileHeader64; + +#define kForkNameLen (256U) + +/// @brief This the executable manifest fork. +typedef struct XCoffForkHeader +{ + NeOS::Char fPropertiesXMLFork[kForkNameLen]; + NeOS::Char fDynamicLoaderFork[kForkNameLen]; + NeOS::Char fCodeSignFork[kForkNameLen]; +} XCoffForkHeader; + +#endif // ifndef INC_XOCFF_H diff --git a/dev/kernel/KernelRsrc.rsrc b/dev/kernel/KernelRsrc.rsrc new file mode 100644 index 00000000..d437c176 --- /dev/null +++ b/dev/kernel/KernelRsrc.rsrc @@ -0,0 +1,25 @@ +#include "CompilerKit/Version.h" + +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904E4" + BEGIN + VALUE "CompanyName", "Amlal El Mahrouss." + VALUE "FileDescription", "NeKernel." + VALUE "FileVersion", KERNEL_VERSION + VALUE "InternalName", "neoskrnl" + VALUE "LegalCopyright", "(c) 2024 Amlal El Mahrouss, all rights reserved." + VALUE "OriginalFilename", "neoskrnl.exe" + VALUE "ProductName", "NeKernel." + VALUE "ProductVersion", KERNEL_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1252 + END +END diff --git a/dev/kernel/MoveAll.ARM64.sh b/dev/kernel/MoveAll.ARM64.sh new file mode 100755 index 00000000..35e0909e --- /dev/null +++ b/dev/kernel/MoveAll.ARM64.sh @@ -0,0 +1,7 @@ +#! /bin/sh + +for file in *.o; do + mv -- "$file" "${file%.o}.obj" +done + +mv *.obj obj/ diff --git a/dev/kernel/MoveAll.X64.sh b/dev/kernel/MoveAll.X64.sh new file mode 100755 index 00000000..1c135d06 --- /dev/null +++ b/dev/kernel/MoveAll.X64.sh @@ -0,0 +1,7 @@ +#! /bin/sh + +for file in *.o; do + mv -- "$file" "${file%.o}.obj" +done + +mv *.obj HALKit/AMD64/*.obj obj/ diff --git a/dev/kernel/NetworkKit/IP.h b/dev/kernel/NetworkKit/IP.h new file mode 100644 index 00000000..4a552d87 --- /dev/null +++ b/dev/kernel/NetworkKit/IP.h @@ -0,0 +1,83 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/DebugOutput.h> +#include <NewKit/Defines.h> +#include <NewKit/Ref.h> +#include <NewKit/KString.h> + +namespace NeOS +{ + class RawIPAddress6; + class RawIPAddress; + class IPFactory; + + class RawIPAddress final + { + private: + explicit RawIPAddress(char bytes[4]); + ~RawIPAddress() = default; + + RawIPAddress& operator=(const RawIPAddress&) = delete; + RawIPAddress(const RawIPAddress&) = default; + + public: + Char* Address(); + + Char& operator[](const Size& index); + + BOOL operator==(const RawIPAddress& ipv6); + BOOL operator!=(const RawIPAddress& ipv6); + + private: + Char fAddr[4]; + + friend IPFactory; // it is the one creating these addresses, thus this + // is why the constructors are private. + }; + + /** + * @brief IPv6 address. + */ + class RawIPAddress6 final + { + private: + explicit RawIPAddress6(char Bytes[8]); + ~RawIPAddress6() = default; + + RawIPAddress6& operator=(const RawIPAddress6&) = delete; + RawIPAddress6(const RawIPAddress6&) = default; + + public: + char* Address() + { + return fAddr; + } + + char& operator[](const Size& index); + + bool operator==(const RawIPAddress6& ipv6); + bool operator!=(const RawIPAddress6& ipv6); + + private: + char fAddr[8]; + + friend IPFactory; + }; + + /** + * @brief IP Creation helpers + */ + class IPFactory final + { + public: + static ErrorOr<KString> ToKString(Ref<RawIPAddress6>& ipv6); + static ErrorOr<KString> ToKString(Ref<RawIPAddress>& ipv4); + static bool IpCheckVersion4(const Char* ip); + }; +} // namespace NeOS diff --git a/dev/kernel/NetworkKit/IPC.h b/dev/kernel/NetworkKit/IPC.h new file mode 100644 index 00000000..e8f0898f --- /dev/null +++ b/dev/kernel/NetworkKit/IPC.h @@ -0,0 +1,91 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.. + + File: IPC.h. + Purpose: IPC protocol. + +------------------------------------------- */ + +#ifndef INC_IPC_H +#define INC_IPC_H + +#include <NewKit/Defines.h> +#include <NewKit/KString.h> +#include <HintsKit/CompilerHint.h> + +/// @file IPC.h +/// @brief IPC comm. protocol. + +/// IA separator. +#define kIPCRemoteSeparator ":" + +/// Interchange address, consists of PID:TEAM. +#define kIPCRemoteInvalid "00:00" + +#define kIPCHeaderMagic (0x4950434) + +namespace NeOS +{ + struct IPC_ADDR; + struct IPC_MSG; + + /// @brief 128-bit IPC address. + struct PACKED IPC_ADDR final + { + UInt64 UserProcessID; + UInt64 UserProcessTeam; + + //////////////////////////////////// + // some operators. + //////////////////////////////////// + + bool operator==(const IPC_ADDR& addr) noexcept; + + bool operator==(IPC_ADDR& addr) noexcept; + + bool operator!=(const IPC_ADDR& addr) noexcept; + + bool operator!=(IPC_ADDR& addr) noexcept; + }; + + typedef struct IPC_ADDR IPC_ADDR; + + enum + { + kIPCLittleEndian = 0, + kIPCBigEndian = 1, + kIPCMixedEndian = 2, + }; + + constexpr inline auto kIPCMsgSize = 6094U; + + /// @brief IPC connection header, message cannot be greater than 6K. + typedef struct IPC_MSG final + { + UInt32 IpcHeaderMagic; // cRemoteHeaderMagic + UInt8 IpcEndianess; // 0 : LE, 1 : BE + SizeT IpcPacketSize; + IPC_ADDR IpcFrom; + IPC_ADDR IpcTo; + UInt32 IpcCRC32; + UInt32 IpcMsg; + UInt32 IpcMsgSz; + UInt8 IpcData[kIPCMsgSize]; + + /// @brief Passes the message to target, could be anything, HTTP packet, JSON or whatever. + static Bool Pass(IPC_MSG* self, IPC_MSG* target) noexcept; + } PACKED IPC_MSG; + + /// @brief Sanitize packet function + /// @retval true packet is correct. + /// @retval false packet is incorrect and process has crashed. + Bool ipc_sanitize_packet(_Input IPC_MSG* pckt_in); + + /// @brief Construct packet function + /// @retval true packet is correct. + /// @retval false packet is incorrect and process has crashed. + Bool ipc_construct_packet(_Output _Input IPC_MSG** pckt_in); +} // namespace NeOS + +#endif // INC_IPC_H diff --git a/dev/kernel/NetworkKit/LTE.h b/dev/kernel/NetworkKit/LTE.h new file mode 100644 index 00000000..e0a0ff64 --- /dev/null +++ b/dev/kernel/NetworkKit/LTE.h @@ -0,0 +1,16 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.. + + File: LTE.h. + Purpose: LTE protocol classes. + +------------------------------------------- */ + +#ifndef _INC_NETWORK_LTE_H_ +#define _INC_NETWORK_LTE_H_ + +#include <NewKit/Defines.h> +#include <NewKit/KString.h> + +#endif // ifndef _INC_NETWORK_LTE_H_ diff --git a/dev/kernel/NetworkKit/MAC.h b/dev/kernel/NetworkKit/MAC.h new file mode 100644 index 00000000..f7283708 --- /dev/null +++ b/dev/kernel/NetworkKit/MAC.h @@ -0,0 +1,36 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Array.h> +#include <NewKit/Defines.h> +#include <NewKit/KString.h> + +#define kMACAddrLen (12) + +namespace NeOS +{ + class MacAddressGetter; + + /// \brief This retrieves the MAC address of the device. + /// \note Listens for the current NIC. + class MacAddressGetter final + { + public: + MacAddressGetter() = default; + ~MacAddressGetter() = default; + + NE_COPY_DEFAULT(MacAddressGetter); + + public: + Array<WideChar, kMACAddrLen>& AsBytes(); + + private: + Array<WideChar, kMACAddrLen> fMacAddress; + }; + +} // namespace NeOS diff --git a/dev/kernel/NetworkKit/NetworkDevice.h b/dev/kernel/NetworkKit/NetworkDevice.h new file mode 100644 index 00000000..c95573f3 --- /dev/null +++ b/dev/kernel/NetworkKit/NetworkDevice.h @@ -0,0 +1,83 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef __INC_NETWORK_DEVICE_H__ +#define __INC_NETWORK_DEVICE_H__ + +#include <KernelKit/DeviceMgr.h> +#include <NetworkKit/IP.h> + +/// @note Can either work with: Ethernet, GPRS, WiFi + +namespace NeOS +{ + struct NetworkDeviceCommand; + class NetworkDevice; + + /** + * \brief Network device interface, establishes a connection to the NIC. + */ + class NetworkDevice final : public IDeviceObject<NetworkDeviceCommand> + { + public: + NetworkDevice(void (*out)(IDeviceObject<NetworkDeviceCommand>*, NetworkDeviceCommand), + void (*in)(IDeviceObject<NetworkDeviceCommand>*, NetworkDeviceCommand), + void (*onCleanup)(void) = nullptr); + + ~NetworkDevice() override; + + public: + NetworkDevice& operator=(const NetworkDevice&) = default; + NetworkDevice(const NetworkDevice&) = default; + + public: + const Char* Name() const override; + Boolean Name(const Char* newStr); + + private: + static constexpr auto cNetworkNameLen = 512; + + Void (*fCleanup)(void); + Char fNetworkName[cNetworkNameLen]; + }; + + struct NetworkDeviceCommand final + { + UInt32 CommandName; + UInt32 CommandType; + UInt32 CommandFlags; + VoidPtr CommandBuffer; + SizeT CommandSizeBuffer; + }; + + /// @brief TCP device. + using TCPNetworkDevice = NetworkDevice; + + /// @brief UDP device. + using UDPNetworkDevice = NetworkDevice; + + /// @brief PPP device. + using PPPNetworkDevice = NetworkDevice; + + /// @brief IPC device. + using IPCNetworkDevice = NetworkDevice; + + /// @brief GRPS device. + using GPRSNetworkDevice = NetworkDevice; + + /// @brief GSM device. + using GSMNetworkDevice = NetworkDevice; + + /// @brief Bluetooth device. + using BTNetworkDevice = NetworkDevice; + + /// @brief LTE device. + using LTENetworkDevice = NetworkDevice; +} // namespace NeOS + +#include <NetworkKit/NetworkDevice.inl> + +#endif // !__INC_NETWORK_DEVICE_H__ diff --git a/dev/kernel/NetworkKit/NetworkDevice.inl b/dev/kernel/NetworkKit/NetworkDevice.inl new file mode 100644 index 00000000..dceae66e --- /dev/null +++ b/dev/kernel/NetworkKit/NetworkDevice.inl @@ -0,0 +1,32 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/*** + Dtor and ctors. +*/ + +namespace NeOS +{ + NetworkDevice::NetworkDevice(void (*out)(IDeviceObject<NetworkDeviceCommand>*, NetworkDeviceCommand), + void (*in)(IDeviceObject<NetworkDeviceCommand>*, NetworkDeviceCommand), + void (*on_cleanup)(void)) + : IDeviceObject<NetworkDeviceCommand>(out, in), fCleanup(on_cleanup) + { + kout << "NetworkDevice initialized.\r"; + + MUST_PASS(out && in && on_cleanup); + } + + NetworkDevice::~NetworkDevice() + { + MUST_PASS(fCleanup); + + kout << "NetworkDevice cleanup.\r"; + + if (fCleanup) + fCleanup(); + } +} // namespace NeOS diff --git a/dev/kernel/NewKit/Array.h b/dev/kernel/NewKit/Array.h new file mode 100644 index 00000000..54c09636 --- /dev/null +++ b/dev/kernel/NewKit/Array.h @@ -0,0 +1,65 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/DebugOutput.h> +#include <NewKit/ErrorOr.h> +#include <NewKit/Defines.h> + +namespace NeOS +{ + template <typename T, SizeT N> + class Array final + { + public: + explicit Array() = default; + ~Array() = default; + + Array& operator=(const Array&) = default; + Array(const Array&) = default; + + T& operator[](const SizeT& at) + { + MUST_PASS(at < this->Count()); + return fArray[at]; + } + + Boolean Empty() + { + return this->Count() > 0; + } + + const SizeT Capacity() + { + return N; + } + + const SizeT Count() + { + return N; + } + + const T* CData() + { + return fArray; + } + + operator bool() + { + return !Empty(); + } + + private: + T fArray[N]; + }; + + template <typename ValueType> + auto make_list(ValueType val) + { + return Array<ValueType, ARRAY_SIZE(val)>{val}; + } +} // namespace NeOS diff --git a/dev/kernel/NewKit/ArrayList.h b/dev/kernel/NewKit/ArrayList.h new file mode 100644 index 00000000..06763b5a --- /dev/null +++ b/dev/kernel/NewKit/ArrayList.h @@ -0,0 +1,63 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + template <typename T> + class ArrayList final + { + public: + explicit ArrayList(T* list, SizeT length) + : fList(reinterpret_cast<T>(list)) + { + } + + ~ArrayList() = default; + + ArrayList& operator=(const ArrayList&) = default; + ArrayList(const ArrayList&) = default; + + T* Data() + { + return fList; + } + + const T* CData() + { + return fList; + } + + T& operator[](int index) const + { + MUST_PASS(index < this->Count()); + return fList[index]; + } + + operator bool() + { + return fList; + } + + SizeT Count() const + { + return fLen; + } + + private: + T* fList{nullptr}; + SizeT fLen{0}; + }; + + template <typename ValueType> + ArrayList<ValueType> make_list(ValueType val) + { + return ArrayList<ValueType>{val}; + } +} // namespace NeOS diff --git a/dev/kernel/NewKit/Atom.h b/dev/kernel/NewKit/Atom.h new file mode 100644 index 00000000..3979b0d1 --- /dev/null +++ b/dev/kernel/NewKit/Atom.h @@ -0,0 +1,47 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + template <typename T> + class Atom final + { + public: + explicit Atom() = default; + ~Atom() = default; + + public: + Atom& operator=(const Atom&) = delete; + Atom(const Atom&) = delete; + + public: + T operator[](Size bit) + { + return (fArrayOfAtoms & (1 << bit)); + } + + void operator|(Size bit) + { + fArrayOfAtoms |= (1 << bit); + } + + friend Boolean operator==(Atom<T>& atomic, const T& idx) + { + return atomic[idx] == idx; + } + + friend Boolean operator!=(Atom<T>& atomic, const T& idx) + { + return atomic[idx] == idx; + } + + private: + T fArrayOfAtoms; + }; +} // namespace NeOS diff --git a/dev/kernel/NewKit/Crc32.h b/dev/kernel/NewKit/Crc32.h new file mode 100644 index 00000000..c3e14413 --- /dev/null +++ b/dev/kernel/NewKit/Crc32.h @@ -0,0 +1,23 @@ +/* + * ======================================================== + * + * NeKernel + * Date Added: 13/02/2023 + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#ifndef CRC32_H +#define CRC32_H + +#include <NewKit/Defines.h> + +#define kCrcCnt (256) + +namespace NeOS +{ + UInt32 ke_calculate_crc32(const Char* crc, Int32 len) noexcept; +} // namespace NeOS + +#endif // !CRC32_H diff --git a/dev/kernel/NewKit/CxxAbi.h b/dev/kernel/NewKit/CxxAbi.h new file mode 100644 index 00000000..e6d83e07 --- /dev/null +++ b/dev/kernel/NewKit/CxxAbi.h @@ -0,0 +1,28 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ +#pragma once + +#include <NewKit/Defines.h> + +#ifndef __TOOLCHAINKIT__ + +#define kAtExitMacDestructors (128) + +struct atexit_func_entry_t +{ + void (*destructor_func)(void*); + void* obj_ptr; + void* dso_handle; +}; + +typedef unsigned uarch_t; + +namespace cxxabiv1 +{ + typedef void* __guard; +} + +#endif // __GNUC__ diff --git a/dev/kernel/NewKit/Defines.h b/dev/kernel/NewKit/Defines.h new file mode 100644 index 00000000..0b0b97e5 --- /dev/null +++ b/dev/kernel/NewKit/Defines.h @@ -0,0 +1,200 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Macros.h> + +#define NEWKIT_VERSION_STR "1.1.0" +#define NEWKIT_VERSION_BCD 0x01100 + +#ifndef __cplusplus +#error NeOS compiles with a C++ compiler. +#endif + +#if __cplusplus <= 201703L +#define char8_t char +#endif + +#ifdef __has_feature +#if !__has_feature(cxx_nullptr) +#if !__has_nullptr +#error !!! You must at least have nullptr featured on your C++ compiler. !!! +#endif +#endif +#endif + +/// @brief The **Kernel** namespace where it's API resides. +namespace NeOS +{ + using voidPtr = void*; + using VoidPtr = void*; + using nullPtr = decltype(nullptr); + using NullPtr = decltype(nullptr); + + using Int = int; + using Int32 = int; + using UShort = unsigned short; + using UInt16 = unsigned short; + using Short = short; + using Int16 = short; + using UInt = unsigned int; + using UInt32 = unsigned int; + using Long = __INT64_TYPE__; + using Int64 = __INT64_TYPE__; + using ULong = __UINT64_TYPE__; + using UInt64 = __UINT64_TYPE__; + using Boolean = bool; + using Bool = bool; + using Char = char; + using UChar = unsigned char; + using UInt8 = unsigned char; + + using SSize = Int64; + using SSizeT = Int64; + using Size = __SIZE_TYPE__; + using SizeT = __SIZE_TYPE__; + using IntPtr = __INTPTR_TYPE__; + using UIntPtr = __UINTPTR_TYPE__; + using IntFast = __INT_FAST32_TYPE__; + using IntFast64 = __INT_FAST64_TYPE__; + using PtrDiff = __PTRDIFF_TYPE__; + + using SInt16 = Int16; + using SInt32 = Int32; + using SInt64 = Int64; + + typedef UIntPtr* Ptr64; + typedef UInt32* Ptr32; + typedef UInt8* Ptr8; + + using Utf8Char = char8_t; + using Utf16Char = char16_t; + using WideChar = wchar_t; + using Utf32Char = char32_t; + + using LongDouble = long double; + using Double = double; + using Float = float; + + typedef UInt32 PhysicalAddressKind; + typedef UIntPtr VirtualAddressKind; + + using Void = void; + + using Lba = UInt64; + + using Char16 = char16_t; + + enum class Endian : UInt8 + { + kEndianInvalid, + kEndianBig, + kEndianLittle, + kEndianMixed, + kEndianCount + }; + + /// @brief Forward object. + /// @tparam Args the object type. + /// @param arg the object. + /// @return object's rvalue + template <typename Args> + inline Args&& forward(Args& arg) + { + return static_cast<Args&&>(arg); + } + + /// @brief Move object. + /// @tparam Args the object type. + /// @param arg the object. + /// @return object's rvalue + template <typename Args> + inline Args&& move(Args&& arg) + { + return static_cast<Args&&>(arg); + } + + /// @brief Encoding interface, used as a proxy to convert T to Char* + /// Used to cast A to B or B to A. + class ICodec + { + public: + explicit ICodec() = default; + virtual ~ICodec() = default; + + ICodec& operator=(const ICodec&) = default; + ICodec(const ICodec&) = default; + + public: + /// @brief Convert type to bytes. + /// @tparam T the type. + /// @param type (a1) the data. + /// @return a1 as Char* + template <typename T> + Char* AsBytes(T type) noexcept + { + return nullptr; + } + + /// @brief Construct from type to class. + /// @tparam T the type to convert. + /// @param type (a1) the data. + /// @return a1 as Char* + template <typename OutputClass, typename FactoryClass> + OutputClass* Construct(Char* type) noexcept + { + FactoryClass class_fac; + return class_fac.template From<OutputClass>(type); + } + + /// @brief Convert T class to Y class. + /// @tparam T the class type of type. + /// @tparam Y the result class. + /// @param type the class to cast. + /// @return the class as Y. + template <typename T, typename Y> + Y As(T type) noexcept + { + if (type.template IsSerializable()) + { + return reinterpret_cast<Char*>(type); + } + + return type.template As<Y>(); + } + }; + + /// \brief Scheduler interface, represents a scheduler object. + /// @note This is used to schedule tasks, such as threads, drivers, user threads, etc. + class ISchedulable + { + public: + explicit ISchedulable() = default; + virtual ~ISchedulable() = default; + + ISchedulable& operator=(const ISchedulable&) = default; + ISchedulable(const ISchedulable&) = default; + + /// @brief Is this object only accepting user tasks? + virtual const Bool IsUser() + { + return NO; + } + + /// @brief Is this object only accepting kernel tasks? + virtual const Bool IsKernel() + { + return NO; + } + + /// @brief Is this object offloading to another CPU? + virtual const Bool HasMP() + { + return NO; + } + }; +} // namespace NeOS diff --git a/dev/kernel/NewKit/ErrorOr.h b/dev/kernel/NewKit/ErrorOr.h new file mode 100644 index 00000000..7c879cc8 --- /dev/null +++ b/dev/kernel/NewKit/ErrorOr.h @@ -0,0 +1,82 @@ +/* + * ======================================================== + * + * NeKernel + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/Ref.h> + +namespace NeOS +{ + using ErrorT = UInt; + + template <typename T> + class ErrorOr final + { + public: + ErrorOr() = default; + ~ErrorOr() = default; + + public: + explicit ErrorOr(Int32 err) + : mId(err) + { + } + + explicit ErrorOr(nullPtr Null) + { + } + + explicit ErrorOr(T* Class) + : mRef(Class) + { + } + + explicit ErrorOr(T Class) + : mRef(Class) + { + } + + ErrorOr& operator=(const ErrorOr&) = default; + ErrorOr(const ErrorOr&) = default; + + ErrorOr& operator=(const Ref<T>& refErr) + { + mRef = refErr; + return *this; + } + + Ref<T>& Leak() + { + return mRef; + } + + Int32 Error() + { + return mId; + } + + operator bool() + { + return mRef; + } + + BOOL HasError() + { + return this->mId > 0; + } + + private: + Ref<T> mRef; + UInt32 mId{0}; + }; + + using ErrorOrAny = ErrorOr<voidPtr>; + +} // namespace NeOS diff --git a/dev/kernel/NewKit/Function.h b/dev/kernel/NewKit/Function.h new file mode 100644 index 00000000..d25c06c1 --- /dev/null +++ b/dev/kernel/NewKit/Function.h @@ -0,0 +1,53 @@ +#ifndef _INC_FUNCTION_H__ +#define _INC_FUNCTION_H__ + +#include <NewKit/Defines.h> + +namespace NeOS +{ + template <typename T, typename... Args> + class Function final + { + public: + Function() = default; + + public: + explicit Function(T (*Fn)(Args... args)) + : fFn(Fn) + { + } + + ~Function() = default; + + Function& operator=(const Function&) = default; + Function(const Function&) = default; + + template <typename... XArgs> + T operator()(Args... args) + { + return fFn(args...); + } + + template <typename... XArgs> + T Call(Args... args) + { + return fFn(args...); + } + + operator bool() + { + return fFn; + } + + bool operator!() + { + return !fFn; + } + + private: + T(*fFn) + (Args... args); + }; +} // namespace NeOS + +#endif // !_INC_FUNCTION_H__ diff --git a/dev/kernel/NewKit/Json.h b/dev/kernel/NewKit/Json.h new file mode 100644 index 00000000..7b53fa4a --- /dev/null +++ b/dev/kernel/NewKit/Json.h @@ -0,0 +1,151 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +// last-rev: 30/01/24 + +#include <CompilerKit/CompilerKit.h> +#include <NewKit/Defines.h> +#include <NewKit/Stream.h> +#include <NewKit/KString.h> +#include <NewKit/Utils.h> + +#define kMaxJsonPath 8196 +#define kJSONLen 256 +#define kJSONNull "[]" + +namespace NeOS +{ + /// @brief JavaScript object class + class Json final + { + public: + explicit Json() + { + auto len = kJSONLen; + KString key = KString(len); + key += kJSONNull; + + this->AsKey() = key; + this->AsValue() = key; + } + + explicit Json(SizeT lhsLen, SizeT rhsLen) + : fKey(lhsLen), fValue(rhsLen) + { + } + + ~Json() = default; + + NE_COPY_DEFAULT(Json); + + const Bool& IsUndefined() + { + return fUndefined; + } + + private: + Bool fUndefined; // is this instance undefined? + KString fKey; + KString fValue; + + public: + /// @brief returns the key of the json + /// @return the key as string view. + KString& AsKey() + { + return fKey; + } + + /// @brief returns the value of the json. + /// @return the key as string view. + KString& AsValue() + { + return fValue; + } + + static Json kNull; + }; + + /// @brief Json stream reader helper. + struct JsonStreamReader final + { + STATIC Json In(const Char* full_array) + { + auto start_val = '{'; + auto end_val = '}'; + Boolean probe_value = false; + + if (full_array[0] != start_val) + { + if (full_array[0] != '[') + return Json::kNull; + + start_val = '['; + end_val = ']'; + + probe_value = true; + } + + SizeT len = rt_string_len(full_array); + + SizeT key_len = 0; + SizeT value_len = 0; + + Json type(kMaxJsonPath, kMaxJsonPath); + + for (SizeT i = 1; i < len; ++i) + { + if (full_array[i] == '\r' || + full_array[i] == '\n') + continue; + + if (probe_value) + { + if (full_array[i] == end_val || + full_array[i] == ',') + { + probe_value = false; + + ++value_len; + } + else + { + type.AsValue().Data()[value_len] = full_array[i]; + + ++value_len; + } + } + else + { + if (start_val == '[') + continue; + + if (full_array[i] == ':') + { + probe_value = true; + type.AsKey().Data()[key_len] = 0; + ++key_len; + } + else + { + type.AsKey().Data()[key_len] = full_array[i]; + + ++key_len; + } + } + } + + type.AsValue().Data()[value_len] = 0; + + return type; + } + }; + + using JsonStream = Stream<JsonStreamReader, Json>; +} // namespace NeOS diff --git a/dev/kernel/NewKit/KString.h b/dev/kernel/NewKit/KString.h new file mode 100644 index 00000000..e7525a9c --- /dev/null +++ b/dev/kernel/NewKit/KString.h @@ -0,0 +1,94 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <NewKit/Defines.h> +#include <NewKit/ErrorOr.h> +#include <NewKit/Utils.h> +#include <NewKit/KernelPanic.h> + +#define cMinimumStringSize 8196 + +namespace NeOS +{ + /// @brief Kernel string class, not dynamic. + class KString final + { + public: + explicit KString() + { + fDataSz = cMinimumStringSize; + + fData = new Char[fDataSz]; + MUST_PASS(fData); + + rt_set_memory(fData, 0, fDataSz); + } + + explicit KString(const SizeT& Sz) + : fDataSz(Sz) + { + MUST_PASS(Sz > 1); + + fData = new Char[Sz]; + MUST_PASS(fData); + + rt_set_memory(fData, 0, Sz); + } + + ~KString() + { + if (fData) + { + delete[] fData; + fData = nullptr; + } + } + + NE_COPY_DEFAULT(KString); + + Char* Data(); + const Char* CData() const; + Size Length() const; + + bool operator==(const Char* rhs) const; + bool operator!=(const Char* rhs) const; + + bool operator==(const KString& rhs) const; + bool operator!=(const KString& rhs) const; + + KString& operator+=(const Char* rhs); + KString& operator+=(const KString& rhs); + + operator bool() + { + return fData; + } + + bool operator!() + { + return fData; + } + + private: + Char* fData{nullptr}; + Size fDataSz{0}; + Size fCur{0}; + + friend class KStringBuilder; + }; + + struct KStringBuilder final + { + static ErrorOr<KString> Construct(const Char* data); + static const Char* FromBool(const Char* fmt, bool n); + static const Char* Format(const Char* fmt, const Char* from); + static bool Equals(const Char* lhs, const Char* rhs); + static bool Equals(const WideChar* lhs, const WideChar* rhs); + }; +} // namespace NeOS diff --git a/dev/kernel/NewKit/KernelPanic.h b/dev/kernel/NewKit/KernelPanic.h new file mode 100644 index 00000000..11f9a05d --- /dev/null +++ b/dev/kernel/NewKit/KernelPanic.h @@ -0,0 +1,74 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + void ke_runtime_check(bool expr, const Char* file, const Char* line); +} + +#define MUST_PASS_COMPILER(EXPR, MSG) static_assert(EXPR, MSG) + +#ifdef TRY +#undef TRY +#endif + +#define TRY(X) \ + { \ + auto fn = X; \ + if ((fn()) == NO) \ + { \ + MUST_PASS(NO); \ + } \ + } + +#ifdef __MUST_PASS +#undef __MUST_PASS +#endif + +#define __MUST_PASS(EXPR, FILE, LINE) \ + NeOS::ke_runtime_check(EXPR, FILE, STRINGIFY(LINE)) + +#ifdef __DEBUG__ +#define MUST_PASS(EXPR) __MUST_PASS((EXPR), __FILE__, __LINE__) +#define assert(EXPR) MUST_PASS(EXPR) +#else +#define MUST_PASS(EXPR) (NeOS::Void)(EXPR) +#define assert(EXPR) (NeOS::Void)(EXPR) +#endif + +enum RUNTIME_CHECK +{ + RUNTIME_CHECK_FAILED = 1111, + RUNTIME_CHECK_POINTER, + RUNTIME_CHECK_EXPRESSION, + RUNTIME_CHECK_FILE, + RUNTIME_CHECK_IPC, + RUNTIME_CHECK_TLS, + RUNTIME_CHECK_HANDSHAKE, + RUNTIME_CHECK_ACPI, + RUNTIME_CHECK_INVALID_PRIVILEGE, + RUNTIME_CHECK_PROCESS, + RUNTIME_CHECK_BAD_BEHAVIOR, + RUNTIME_CHECK_BOOTSTRAP, + RUNTIME_CHECK_UNEXCPECTED, + RUNTIME_CHECK_FILESYSTEM, + RUNTIME_CHECK_VIRTUAL_OUT_OF_MEM, + RUNTIME_CHECK_PAGE, + RUNTIME_CHECK_INVALID, + RUNTIME_CHECK_COUNT, +}; + +typedef enum RUNTIME_CHECK RTL_RUNTIME_CHECK; + +namespace NeOS +{ + void ke_panic(const Int32& id, const Char* message = nullptr); +} // namespace NeOS diff --git a/dev/kernel/NewKit/Macros.h b/dev/kernel/NewKit/Macros.h new file mode 100644 index 00000000..637a2a30 --- /dev/null +++ b/dev/kernel/NewKit/Macros.h @@ -0,0 +1,149 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#ifndef KIB +#define KIB(X) (NeOS::UInt64)((X) / 1024) +#endif + +#ifndef kib_cast +#define kib_cast(X) (NeOS::UInt64)((X)*1024) +#endif + +#ifndef MIB +#define MIB(X) (NeOS::UInt64)((NeOS::UInt64)KIB(X) / 1024) +#endif + +#ifndef mib_cast +#define mib_cast(X) (NeOS::UInt64)((NeOS::UInt64)kib_cast(X) * 1024) +#endif + +#ifndef GIB +#define GIB(X) (NeOS::UInt64)((NeOS::UInt64)MIB(X) / 1024) +#endif + +#ifndef gib_cast +#define gib_cast(X) (NeOS::UInt64)((NeOS::UInt64)mib_cast(X) * 1024) +#endif + +#ifndef TIB +#define TIB(X) (NeOS::UInt64)((NeOS::UInt64)GIB(X) / 1024) +#endif + +#ifndef tib_cast +#define tib_cast(X) ((NeOS::UInt64)gib_cast(X) * 1024) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) \ + (((sizeof(a) / sizeof(*(a))) / \ + (static_cast<NeOS::Size>(!(sizeof(a) % sizeof(*(a))))))) +#endif + +#define DEPRECATED ATTRIBUTE(deprecated) + +#ifndef ALIGN +#define ALIGN(X) __attribute__((aligned(X))) +#endif // #ifndef ALIGN + +#ifndef ATTRIBUTE +#define ATTRIBUTE(...) __attribute__((__VA_ARGS__)) +#endif // #ifndef ATTRIBUTE + +#ifndef __NE_VER__ +#define __NE_VER__ (2024) +#endif // !__NE_VER__ + +#ifndef EXTERN +#define EXTERN extern +#endif + +#ifndef EXTERN_C +#define EXTERN_C extern "C" +#endif + +#ifndef MAKE_ENUM +#define MAKE_ENUM(NAME) \ + enum NAME \ + { +#endif + +#ifndef END_ENUM +#define END_ENUM() \ + } \ + ; +#endif + +#ifndef MAKE_STRING_ENUM +#define MAKE_STRING_ENUM(NAME) \ + namespace NAME \ + { +#endif + +#ifndef ENUM_STRING +#define ENUM_STRING(NAME, VAL) inline constexpr const char* e##NAME = VAL +#endif + +#ifndef END_STRING_ENUM +#define END_STRING_ENUM() } +#endif + +#ifndef RTL_ALLOCA +#define RTL_ALLOCA(sz) __builtin_alloca(sz) +#endif // #ifndef RTL_ALLOCA + +#ifndef CANT_REACH +#define CANT_REACH() __builtin_unreachable() +#endif + +#define kInvalidAddress 0xFBFBFBFBFBFBFBFB +#define kBadAddress 0x0000000000000000 +#define kMaxAddr 0xFFFFFFFFFFFFFFFF +#define kPathLen 0x100 + +#define PACKED ATTRIBUTE(packed) +#define NO_EXEC ATTRIBUTE(noexec) + +#define EXTERN extern +#define STATIC static + +#define CONST const + +#define STRINGIFY(X) #X +#define NE_UNUSED(X) ((NeOS::Void)X) + +#ifndef RGB +#define RGB(R, G, B) (NeOS::UInt32)(R | G << 0x8 | B << 0x10) +#endif // !RGB + +#ifdef __NE_AMD64__ +#define dbg_break_point() asm volatile("int $3") +#else +#define dbg_break_point() ((void)0) +#endif + +#define RTL_ENDIAN(address, value) \ + (((reinterpret_cast<NeOS::Char*>(address)[0]) == (value)) \ + ? (NeOS::Endian::kEndianBig) \ + : (NeOS::Endian::kEndianLittle)) + +#define Yes true +#define No false + +#define YES true +#define NO false + +#define TRUE true +#define FALSE false + +#define BOOL NeOS::Boolean + +#ifdef RTL_INIT_OBJECT +#undef RTL_INIT_OBJECT +#endif // ifdef RTL_INIT_OBJECT + +#define RTL_INIT_OBJECT(OBJ, TYPE, ...) TYPE OBJ = TYPE(__VA_ARGS__) diff --git a/dev/kernel/NewKit/MutableArray.h b/dev/kernel/NewKit/MutableArray.h new file mode 100644 index 00000000..bfb432de --- /dev/null +++ b/dev/kernel/NewKit/MutableArray.h @@ -0,0 +1,239 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ +#pragma once + +#include <CompilerKit/CompilerKit.h> +#include <NewKit/Array.h> +#include <NewKit/Defines.h> + +#define TRY_FIND_NODE(NAME, NODE) \ + auto* NAME = NODE; \ + while (NAME) \ + { \ + if (NAME->fIndex == Index) \ + return NAME->fVal; \ + NAME = NAME->fNext; \ + } + +#define TRY_FIND_NODE2(NAME, NODE) \ + auto* NAME = NODE; \ + while (NAME) \ + { \ + if (NAME->fIndex == Index) \ + return Ref<T>{NAME->fVal}; \ + NAME = NAME->fNext; \ + } + +#define TRY_REMOVE_NODE(NODE) \ + if (NODE && NODE->fIndex == Index) \ + { \ + NODE->fUsed = false; \ + NODE->fIndex = 0; \ + \ + return true; \ + } + +// FIXME: this is a shitty algorithm, which is consumer hungry. +// Remove and occurences of that, and remove that class. +namespace NeOS +{ + template <typename T> + class MutableArray; + + template <typename T, T _PlaceHolderValue> + class NullableMutableArray; + + template <typename T> + class MutableLinkedList + { + public: + T fVal; + SizeT fIndex{0}; + Boolean fUsed{false}; + + MutableLinkedList* fPrev{nullptr}; + MutableLinkedList* fNext{nullptr}; + }; + + template <typename T, T _PlaceHolderValue> + class NullableMutableArray + { + public: + // explicit this. + explicit NullableMutableArray() + : fFirstNode(new MutableLinkedList<T>()) + { + } + + /* + * We free all the nodes allocated by the array + * and store the next one inside "NextIt" + */ + + virtual ~NullableMutableArray() + { + auto* It = fFirstNode; + MutableLinkedList<T>* NextIt = nullptr; + + while (It) + { + NextIt = It->fNext; + delete It; + + It = NextIt; + } + } + + NullableMutableArray& operator=(const NullableMutableArray&) = default; + NullableMutableArray(const NullableMutableArray&) = default; + + operator bool() + { + return Count() > 1; + } + + public: + T operator[](const SizeT& Index) const + { + TRY_FIND_NODE(first, fFirstNode); + TRY_FIND_NODE(last, fLastNode); + + return _PlaceHolderValue; + } + + SizeT Count() const + { + return fNodeCount; + } + + public: + Boolean Remove(const SizeT& Index) + { + TRY_REMOVE_NODE(fFirstNode); + TRY_REMOVE_NODE(fLastNode); + + return false; + } + + Boolean Add(const T val) + { + auto* iterationNode = fFirstNode; + MUST_PASS(iterationNode); + + while (iterationNode) + { + if (!iterationNode->fUsed) + { + iterationNode->fVal = val; + iterationNode->fIndex = 0; + + iterationNode->fUsed = true; + + ++fNodeCount; + + return true; + } + + iterationNode = iterationNode->fNext; + } + + return false; + } + + private: + /* Avoid useless lookups */ + MutableLinkedList<T>* fLastNode{nullptr}; + MutableLinkedList<T>* fFirstNode{nullptr}; + + /* Number of nodes inside of this dynamic array. */ + NeOS::SizeT fNodeCount{0}; + + private: + // don't remove that + friend MutableArray<T>; + }; + + template <typename T> + class MutableArray : public NullableMutableArray<voidPtr, nullptr> + { + public: + // explicit this. + explicit MutableArray() = default; + virtual ~MutableArray() = default; + + NE_COPY_DEFAULT(MutableArray) + + public: + Boolean Add(const T val) + { + auto* iterationNode = fFirstNode; + + if (!iterationNode) + { + fFirstNode = new MutableLinkedList<T>(); + iterationNode = fFirstNode; + } + + MUST_PASS(iterationNode); + + while (iterationNode) + { + if (!iterationNode->fUsed) + { + iterationNode->fVal = val; + iterationNode->fIndex = 0; + + iterationNode->fUsed = true; + + ++fNodeCount; + + return true; + } + + iterationNode = iterationNode->fNext; + } + + return false; + } + + public: + Ref<T> operator[](const SizeT& Index) const + { + TRY_FIND_NODE2(first, fFirstNode); + TRY_FIND_NODE2(last, fLastNode); + + return {}; + } + + SizeT Count() const + { + return fNodeCount; + } + + bool Contains(T& value) noexcept + { + MutableLinkedList<T>* first = fFirstNode; + + while (first) + { + if (first->fVal == value && first->fUsed) + return true; + + first = first->fNext; + } + + return false; + } + + private: + /* Avoid useless lookups */ + MutableLinkedList<T>* fLastNode{nullptr}; + MutableLinkedList<T>* fFirstNode{nullptr}; + + /* Number of nodes inside of this dynamic array. */ + NeOS::SizeT fNodeCount{0}; + }; +} // namespace NeOS diff --git a/dev/kernel/NewKit/New.h b/dev/kernel/NewKit/New.h new file mode 100644 index 00000000..5e1545db --- /dev/null +++ b/dev/kernel/NewKit/New.h @@ -0,0 +1,20 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/MemoryMgr.h> + +/// @note compatible with tk too. +typedef __SIZE_TYPE__ size_t; + +void* operator new(size_t ptr); +void* operator new[](size_t ptr); + +void operator delete(void* ptr); +void operator delete(void* ptr, unsigned long); +void operator delete[](void* ptr); diff --git a/dev/kernel/NewKit/NewKit.h b/dev/kernel/NewKit/NewKit.h new file mode 100644 index 00000000..69d39824 --- /dev/null +++ b/dev/kernel/NewKit/NewKit.h @@ -0,0 +1,20 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Array.h> +#include <NewKit/ArrayList.h> +#include <NewKit/ErrorOr.h> +#include <NewKit/Json.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/MutableArray.h> +#include <NewKit/New.h> +#include <NewKit/OwnPtr.h> +#include <NewKit/Ref.h> +#include <NewKit/Stream.h> +#include <NewKit/Utils.h> diff --git a/dev/kernel/NewKit/OwnPtr.h b/dev/kernel/NewKit/OwnPtr.h new file mode 100644 index 00000000..169f16d9 --- /dev/null +++ b/dev/kernel/NewKit/OwnPtr.h @@ -0,0 +1,94 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/Ref.h> + +namespace NeOS +{ + template <typename T> + class OwnPtr; + + template <typename T> + class NonNullRefPtr; + + template <typename T> + class OwnPtr final + { + public: + OwnPtr() + { + } + ~OwnPtr() + { + this->Delete(); + } + + OwnPtr& operator=(const OwnPtr&) = default; + OwnPtr(const OwnPtr&) = default; + + public: + template <typename... Args> + bool New(Args&&... arg) + { + if (fCls) + { + return false; + } + + fCls = new T(arg...); + return fCls; + } + + void Delete() + { + if (fCls) + delete fCls; + + fCls = nullptr; + } + + T* operator->() const + { + return fCls; + }; + T* Raw() + { + return fCls; + } + + Ref<T> AsRef() + { + return Ref<T>(fCls); + } + + operator bool() + { + return fCls; + } + bool operator!() + { + return !fCls; + } + + private: + T* fCls; + }; + + template <typename T, typename... Args> + OwnPtr<T> make_ptr(Args... args) + { + OwnPtr<T> ret; + ret.template New<Args...>(forward(args)...); + MUST_PASS(ret); + + return ret; + } +} // namespace NeOS diff --git a/dev/kernel/NewKit/PageMgr.h b/dev/kernel/NewKit/PageMgr.h new file mode 100644 index 00000000..3d8e1f9a --- /dev/null +++ b/dev/kernel/NewKit/PageMgr.h @@ -0,0 +1,81 @@ +// a way to create and find our pages. +// I'm thinking about a separate way of getting a paged area. + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/Ref.h> + +namespace NeOS +{ + class PageMgr; + + class PTEWrapper final + { + public: + explicit PTEWrapper(Boolean Rw = false, Boolean User = false, Boolean ExecDisable = false, UIntPtr Address = 0); + + ~PTEWrapper(); + + PTEWrapper& operator=(const PTEWrapper&) = default; + PTEWrapper(const PTEWrapper&) = default; + + public: + const UIntPtr VirtualAddress(); + + Void NoExecute(const bool enable = false); + Bool NoExecute(); + + operator bool() + { + return fVirtAddr; + } + + bool Reclaim(); + bool Shareable(); + bool Present(); + bool Access(); + + private: + Boolean fRw; + Boolean fUser; + Boolean fExecDisable; + UIntPtr fVirtAddr; + Boolean fCache; + Boolean fShareable; + Boolean fWt; + Boolean fPresent; + Boolean fAccessed; + + private: + friend class PageMgr; + friend class Pmm; + }; + + struct PageMgr final + { + public: + PageMgr() = default; + ~PageMgr() = default; + + PageMgr& operator=(const PageMgr&) = default; + PageMgr(const PageMgr&) = default; + + public: + PTEWrapper Request(Boolean Rw, Boolean User, Boolean ExecDisable, SizeT Sz); + bool Free(Ref<PTEWrapper>& wrapper); + + private: + void FlushTLB(); + + private: + friend PTEWrapper; + friend class Pmm; + }; +} // namespace NeOS diff --git a/dev/kernel/NewKit/Pair.h b/dev/kernel/NewKit/Pair.h new file mode 100644 index 00000000..05a95ff3 --- /dev/null +++ b/dev/kernel/NewKit/Pair.h @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + class Pair; +} // namespace NeOS diff --git a/dev/kernel/NewKit/Pmm.h b/dev/kernel/NewKit/Pmm.h new file mode 100644 index 00000000..97bdc0eb --- /dev/null +++ b/dev/kernel/NewKit/Pmm.h @@ -0,0 +1,44 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/PageMgr.h> +#include <NewKit/Ref.h> + +namespace NeOS +{ + class Pmm; + class PTEWrapper; + + class Pmm final + { + public: + explicit Pmm(); + ~Pmm(); + + Pmm& operator=(const Pmm&) = delete; + Pmm(const Pmm&) = default; + + Ref<PTEWrapper> RequestPage(Boolean user = false, Boolean readWrite = false); + Boolean FreePage(Ref<PTEWrapper> refPage); + + Boolean ToggleRw(Ref<PTEWrapper> refPage, Boolean enable = true); + Boolean TogglePresent(Ref<PTEWrapper> refPage, Boolean enable = true); + Boolean ToggleUser(Ref<PTEWrapper> refPage, Boolean enable = true); + Boolean ToggleShare(Ref<PTEWrapper> refPage, Boolean enable = true); + + /// @brief Get the page manager of this. + Ref<PageMgr>& Leak() + { + return fPageMgr; + } + + private: + Ref<PageMgr> fPageMgr; + }; +} // namespace NeOS diff --git a/dev/kernel/NewKit/Ref.h b/dev/kernel/NewKit/Ref.h new file mode 100644 index 00000000..e41bf3bc --- /dev/null +++ b/dev/kernel/NewKit/Ref.h @@ -0,0 +1,108 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef _NEWKIT_REF_H_ +#define _NEWKIT_REF_H_ + +#include <NewKit/Defines.h> +#include <NewKit/KernelPanic.h> +#include <KernelKit/MemoryMgr.h> + +namespace NeOS +{ + template <typename T> + class Ref final + { + public: + Ref() = default; + + ~Ref() + { + if (mm_is_valid_heap(fClass)) + delete fClass; + } + + public: + Ref(T* cls) + : fClass(cls) + { + } + + Ref(T cls) + : fClass(&cls) + { + } + + Ref& operator=(T ref) + { + if (!fClass) + return *this; + + fClass = &ref; + return *this; + } + + public: + T operator->() const + { + MUST_PASS(*fClass); + return *fClass; + } + + T& Leak() noexcept + { + return *fClass; + } + + T& TryLeak() const noexcept + { + MUST_PASS(*fClass); + return *fClass; + } + + T operator*() + { + return *fClass; + } + + operator bool() noexcept + { + return fClass; + } + + private: + T* fClass{nullptr}; + }; + + template <typename T> + class NonNullRef final + { + public: + NonNullRef() = delete; + NonNullRef(nullPtr) = delete; + + NonNullRef(T* ref) + : fRef(ref) + { + MUST_PASS(ref); + } + + Ref<T>& operator->() + { + MUST_PASS(fRef); + return fRef; + } + + NonNullRef& operator=(const NonNullRef<T>& ref) = delete; + NonNullRef(const NonNullRef<T>& ref) = default; + + private: + Ref<T> fRef{nullptr}; + }; +} // namespace NeOS + +#endif // ifndef _NEWKIT_REF_H_ diff --git a/dev/kernel/NewKit/Stream.h b/dev/kernel/NewKit/Stream.h new file mode 100644 index 00000000..541d3389 --- /dev/null +++ b/dev/kernel/NewKit/Stream.h @@ -0,0 +1,58 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/Ref.h> + +namespace NeOS +{ + template <typename StreamTrait, typename Kind> + class Stream final + { + public: + explicit Stream(Ref<Stream> ref) + : fStream(ref) + { + } + + ~Stream() = default; + + Stream& operator=(const Stream&) = default; + Stream(const Stream&) = default; + + template <typename Data> + friend Stream<StreamTrait, Kind>& operator>>(Stream<StreamTrait, Kind>& Ks, Ref<Data>& Buf) + { + Ks.fKind = Ks.fStream->In(Buf); + return *Ks; + } + + template <typename Data> + friend Stream<StreamTrait, Kind>& operator<<(Stream<StreamTrait, Kind>& Ks, Ref<Data>& Buf) + { + Ks.fKind = Buf; + Ks.fStream->Out(Buf.Leak()); + return *Ks; + } + + Ref<StreamTrait>& AsStreamTrait() + { + return fStream; + } + + Ref<Kind>& AsType() + { + return fKind; + } + + private: + Ref<StreamTrait> fStream; + Ref<Kind> fKind; + }; +} // namespace NeOS diff --git a/dev/kernel/NewKit/Utils.h b/dev/kernel/NewKit/Utils.h new file mode 100644 index 00000000..3df823ef --- /dev/null +++ b/dev/kernel/NewKit/Utils.h @@ -0,0 +1,30 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +namespace NeOS +{ + Int rt_copy_memory(const voidPtr src, voidPtr dst, Size len); + Int rt_move_memory(const voidPtr src, voidPtr dst, Size len); + voidPtr rt_set_memory(voidPtr dst, UInt32 val, Size len); + void rt_zero_memory(voidPtr pointer, Size len); + Int rt_string_cmp(const Char* src, const Char* cmp, Size len); + const Char* rt_alloc_string(const Char* text); + Size rt_string_len(const Char* str); + Size rt_string_len(const Char* str, SizeT _len); + Boolean rt_to_string(Char* str_out, UInt64 base, Int32 limit); + Boolean rt_is_newln(Char chr); + Boolean rt_is_space(Char chr); + Int32 rt_is_alnum(Int32 character); + Int rt_to_uppercase(Int c); + Int rt_to_lower(Int c); + voidPtr rt_string_in_string(const Char* in, const Char* needle); + char* rt_string_has_char(Char* str, const Char chr); +} // namespace NeOS diff --git a/dev/kernel/NewKit/Variant.h b/dev/kernel/NewKit/Variant.h new file mode 100644 index 00000000..82be6636 --- /dev/null +++ b/dev/kernel/NewKit/Variant.h @@ -0,0 +1,72 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <NewKit/KString.h> +#include <NewKit/Json.h> + +namespace NeOS +{ + class Variant final + { + public: + enum class VariantKind + { + kString, + kBlob, + kNull, + kJson, + kXML, + }; + + public: + explicit Variant() = delete; + + public: + NE_COPY_DEFAULT(Variant); + + ~Variant() = default; + + public: + explicit Variant(KString* stringView) + : fPtr((VoidPtr)stringView), fKind(VariantKind::kString) + { + } + + explicit Variant(Json* json) + : fPtr((VoidPtr)json), fKind(VariantKind::kJson) + { + } + + explicit Variant(nullPtr ptr) + : fPtr(ptr), fKind(VariantKind::kNull) + { + } + + explicit Variant(VoidPtr ptr) + : fPtr(ptr), fKind(VariantKind::kBlob) + { + } + + public: + const Char* ToString(); + VoidPtr Leak(); + + template <typename T> + T* As() + { + return reinterpret_cast<T*>(fPtr); + } + + VariantKind& Kind(); + + private: + voidPtr fPtr{nullptr}; + VariantKind fKind{VariantKind::kNull}; + }; +} // namespace NeOS diff --git a/dev/kernel/SignalKit/Signals.h b/dev/kernel/SignalKit/Signals.h new file mode 100644 index 00000000..09d392f6 --- /dev/null +++ b/dev/kernel/SignalKit/Signals.h @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> + +typedef NeOS::UInt32 SignalKind; + +#define SIGKILL 0 +#define SIGPAUS 1 +#define SIGEXEC 2 +#define SIGTRAP 3 +#define SIGABRT 4 +#define SIGCONT 5 + +#define SIGBREK 666 +#define SIGATCH 661 +#define SIGDTCH 662
\ No newline at end of file diff --git a/dev/kernel/StorageKit/AHCI.h b/dev/kernel/StorageKit/AHCI.h new file mode 100644 index 00000000..43e81ba0 --- /dev/null +++ b/dev/kernel/StorageKit/AHCI.h @@ -0,0 +1,60 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/DriveMgr.h> +#include <NewKit/OwnPtr.h> + +namespace NeOS +{ + class AHCIDeviceInterface NE_DEVICE<MountpointInterface*> + { + public: + explicit AHCIDeviceInterface(void (*out)(IDeviceObject* self, MountpointInterface* out), + void (*in)(IDeviceObject* self, MountpointInterface* in), + void (*cleanup)(void)); + + virtual ~AHCIDeviceInterface() override; + + public: + AHCIDeviceInterface& operator=(const AHCIDeviceInterface&) = default; + AHCIDeviceInterface(const AHCIDeviceInterface&) = default; + + const Char* Name() const override; + + const UInt16& GetPortsImplemented() + { + return this->fPortsImplemented; + } + + Void SetPortsImplemented(const UInt16& pi) + { + MUST_PASS(pi > 0); + this->fPortsImplemented = pi; + } + + const UInt32& GetIndex() + { + return this->fDriveIndex; + } + + Void SetIndex(const UInt32& drv) + { + MUST_PASS(MountpointInterface::kDriveIndexInvalid != drv); + this->fDriveIndex = drv; + } + + private: + Void (*fCleanup)(Void) = {nullptr}; + UInt16 fPortsImplemented{0U}; + UInt32 fDriveIndex{0U}; + }; + + UInt16 sk_init_ahci_device(BOOL atapi); + ErrorOr<AHCIDeviceInterface> sk_acquire_ahci_device(Int32 drv_index); +} // namespace NeOS diff --git a/dev/kernel/StorageKit/ATA.h b/dev/kernel/StorageKit/ATA.h new file mode 100644 index 00000000..5698fe85 --- /dev/null +++ b/dev/kernel/StorageKit/ATA.h @@ -0,0 +1,39 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/DriveMgr.h> +#include <NewKit/OwnPtr.h> +#include <NewKit/Utils.h> + +namespace NeOS +{ + /// @brief ATA device interface type. + class ATADeviceInterface : public IDeviceObject<MountpointInterface*> + { + public: + explicit ATADeviceInterface(void (*Out)(IDeviceObject*, MountpointInterface* outpacket), + void (*In)(IDeviceObject*, MountpointInterface* inpacket), + void (*Cleanup)(void)); + + virtual ~ATADeviceInterface(); + + public: + ATADeviceInterface& operator<<(MountpointInterface* Data) override; + ATADeviceInterface& operator>>(MountpointInterface* Data) override; + + public: + ATADeviceInterface& operator=(const ATADeviceInterface&) = default; + ATADeviceInterface(const ATADeviceInterface&) = default; + + const Char* Name() const override; + + private: + void (*fCleanup)(void) = {nullptr}; + }; +} // namespace NeOS diff --git a/dev/kernel/StorageKit/NVME.h b/dev/kernel/StorageKit/NVME.h new file mode 100644 index 00000000..22300726 --- /dev/null +++ b/dev/kernel/StorageKit/NVME.h @@ -0,0 +1,34 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/DriveMgr.h> + +namespace NeOS +{ + class NVMEDeviceInterface final NE_DEVICE<MountpointInterface*> + { + public: + explicit NVMEDeviceInterface(Void (*out)(IDeviceObject*, MountpointInterface* out_packet), + Void (*in)(IDeviceObject*, MountpointInterface* in_packet), + Void (*cleanup)(Void)); + + ~NVMEDeviceInterface() override; + + public: + NE_COPY_DEFAULT(NVMEDeviceInterface); + + const Char* Name() const override; + + public: + OwnPtr<MountpointInterface*> operator()(UInt32 dma_low, UInt32 dma_high, SizeT dma_sz); + + private: + Void (*fCleanup)(Void) = {nullptr}; + }; +} // namespace NeOS diff --git a/dev/kernel/StorageKit/PRDT.h b/dev/kernel/StorageKit/PRDT.h new file mode 100644 index 00000000..40ba11e0 --- /dev/null +++ b/dev/kernel/StorageKit/PRDT.h @@ -0,0 +1,36 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <KernelKit/PCI/DMA.h> +#include <KernelKit/PCI/Iterator.h> +#include <NewKit/Ref.h> + +#define kPrdtTransferSize (sizeof(NeOS::UShort)) + +namespace NeOS +{ + /// @brief Tranfer information about PRD. + enum kPRDTTransfer + { + kPRDTTransferInProgress, + kPRDTTransferIsDone, + kPRDTTransferCount, + }; + + /// @brief Physical Region Descriptor Table. + struct PRDT + { + UInt32 fPhysAddress; + UInt32 fSectorCount; + UInt8 fEndBit; + }; + + void construct_prdt(Ref<PRDT>& prd); + + EXTERN_C Int32 kPRDTTransferStatus; +} // namespace NeOS diff --git a/dev/kernel/StorageKit/SCSI.h b/dev/kernel/StorageKit/SCSI.h new file mode 100644 index 00000000..fc526447 --- /dev/null +++ b/dev/kernel/StorageKit/SCSI.h @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <modules/SCSI/SCSI.h> + +extern const scsi_packet_type<12> kCDRomPacketTemplate; diff --git a/dev/kernel/StorageKit/StorageKit.h b/dev/kernel/StorageKit/StorageKit.h new file mode 100644 index 00000000..a0f1a2d1 --- /dev/null +++ b/dev/kernel/StorageKit/StorageKit.h @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#define kDriveSectorSizeHDD (512U) +#define kDriveSectorSizeSSD (512U) +#define kDriveSectorSizeOptical (2048) + +namespace NeOS +{ + template <typename T> + class IDeviceObject; + + class NVMEDeviceInterface; + class AHCIDeviceInterface; + class ATADeviceInterface; + class SCSIDeviceInterface; +} // namespace NeOS diff --git a/dev/kernel/SystemKit/SwapDisk.h b/dev/kernel/SystemKit/SwapDisk.h new file mode 100644 index 00000000..11cc6332 --- /dev/null +++ b/dev/kernel/SystemKit/SwapDisk.h @@ -0,0 +1,46 @@ + +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss Labs, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.h> +#include <CompilerKit/CompilerKit.h> + +#define kSwapBlockMaxSize (mib_cast(16)) +#define kSwapPageFile "/boot/pagefile.sys" + +/// @file SwapDisk.h +/// @brief Virtual memory swap disk. + +namespace NeOS +{ + struct SWAP_DISK_HEADER; + + /// @brief This class is a disk swap delegate for any data. available as a syscall too. + class SwapDisk final + { + public: + explicit SwapDisk() = default; + ~SwapDisk() = default; + + NE_COPY_DEFAULT(SwapDisk); + + BOOL Write(const Char* fork_name, const SizeT fork_name_len, SWAP_DISK_HEADER* data, const SizeT data_len); + SWAP_DISK_HEADER* Read(const Char* fork_name, const SizeT fork_name_len, const SizeT data_len); + }; + + typedef struct SWAP_DISK_HEADER + { + UInt32 fMagic; + SizeT fHeaderSz; + UInt64 fTeamID; + UInt64 fProcessID; + UInt64 fVirtualAddress; + SizeT fBlobSz; + Char fBlob[]; + } PACKED SWAP_DISK_HEADER; +} // namespace NeOS diff --git a/dev/kernel/amd64-ci.make b/dev/kernel/amd64-ci.make new file mode 100644 index 00000000..534e896c --- /dev/null +++ b/dev/kernel/amd64-ci.make @@ -0,0 +1,79 @@ +################################################## +# (c) Amlal EL Mahrouss, all rights reserved. +# This is the neoskrnl's makefile. +################################################## + +CXX = x86_64-w64-mingw32-g++ +LD = x86_64-w64-mingw32-ld +CCFLAGS = -fshort-wchar -c -D__NE_AMD64__ -mno-red-zone -fno-rtti -fno-exceptions -std=c++20 -D__NE_SUPPORT_NX__ -O0 -I../Vendor -D__FSKIT_INCLUDES_NEFS__ -D__NEOSKRNL__ -D__HAVE_NE_APIS__ -D__FREESTANDING__ -D__NE_VIRTUAL_MEMORY_SUPPORT__ -D__NE_AUTO_FORMAT__ -D__NE__ -I./ -I../ -I../zba + +ASM = nasm + +DISK_DRV = + +ifneq ($(ATA_PIO_SUPPORT), ) +DISK_DRV = -D__ATA_PIO__ +endif + +ifneq ($(ATA_DMA_SUPPORT), ) +DISK_DRV = -D__ATA_DMA__ +endif + +ifneq ($(AHCI_SUPPORT), ) +DISK_DRV = -D__AHCI__ +endif + +ifneq ($(DEBUG_SUPPORT), ) +DEBUG_MACRO = -D__DEBUG__ +endif + +COPY = cp + +# Add assembler, linker, and object files variables. +ASMFLAGS = -f win64 + +# Kernel subsystem is 17 and entrypoint is hal_init_platform +LDFLAGS = -e hal_init_platform --subsystem=17 --image-base 0x4000000 +LDOBJ = obj/*.obj + +# This file is the Kernel, responsible of task, memory, driver, sci, disk and device management. +KERNEL_IMG = neoskrnl.exe + +.PHONY: error +error: + @echo "=== ERROR ===" + @echo "=> Use a specific target." + +MOVEALL=./MoveAll.X64.sh +WINDRES=x86_64-w64-mingw32-windres + +.PHONY: newos-amd64-epm +newos-amd64-epm: clean + $(WINDRES) KernelRsrc.rsrc -O coff -o KernelRsrc.obj + $(CXX) $(CCFLAGS) $(DISK_DRV) $(DEBUG_MACRO) $(wildcard src/*.cc) $(wildcard HALKit/AMD64/PCI/*.cc) $(wildcard src/Network/*.cc) $(wildcard src/Storage/*.cc) $(wildcard src/FS/*.cc) $(wildcard HALKit/AMD64/Storage/*.cc) $(wildcard HALKit/AMD64/*.cc) $(wildcard src/System/*.cc) $(wildcard HALKit/AMD64/*.s) + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalInterruptAPI.asm + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalCommonAPI.asm + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalBoot.asm + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalUtils.asm + $(MOVEALL) + +OBJCOPY=x86_64-w64-mingw32-objcopy + +.PHONY: link-amd64-epm +link-amd64-epm: + $(LD) $(LDFLAGS) $(LDOBJ) -o $(KERNEL_IMG) + +.PHONY: all +all: newos-amd64-epm link-amd64-epm + @echo "Kernel => OK." + +.PHONY: help +help: + @echo "=== HELP ===" + @echo "all: Build Kernel and link it." + @echo "link-amd64-epm: Link Kernel for EPM based disks." + @echo "newos-amd64-epm: Build Kernel for EPM based disks." + +.PHONY: clean +clean: + rm -f $(LDOBJ) $(wildcard *.o) $(KERNEL_IMG) diff --git a/dev/kernel/amd64-desktop.make b/dev/kernel/amd64-desktop.make new file mode 100644 index 00000000..534e896c --- /dev/null +++ b/dev/kernel/amd64-desktop.make @@ -0,0 +1,79 @@ +################################################## +# (c) Amlal EL Mahrouss, all rights reserved. +# This is the neoskrnl's makefile. +################################################## + +CXX = x86_64-w64-mingw32-g++ +LD = x86_64-w64-mingw32-ld +CCFLAGS = -fshort-wchar -c -D__NE_AMD64__ -mno-red-zone -fno-rtti -fno-exceptions -std=c++20 -D__NE_SUPPORT_NX__ -O0 -I../Vendor -D__FSKIT_INCLUDES_NEFS__ -D__NEOSKRNL__ -D__HAVE_NE_APIS__ -D__FREESTANDING__ -D__NE_VIRTUAL_MEMORY_SUPPORT__ -D__NE_AUTO_FORMAT__ -D__NE__ -I./ -I../ -I../zba + +ASM = nasm + +DISK_DRV = + +ifneq ($(ATA_PIO_SUPPORT), ) +DISK_DRV = -D__ATA_PIO__ +endif + +ifneq ($(ATA_DMA_SUPPORT), ) +DISK_DRV = -D__ATA_DMA__ +endif + +ifneq ($(AHCI_SUPPORT), ) +DISK_DRV = -D__AHCI__ +endif + +ifneq ($(DEBUG_SUPPORT), ) +DEBUG_MACRO = -D__DEBUG__ +endif + +COPY = cp + +# Add assembler, linker, and object files variables. +ASMFLAGS = -f win64 + +# Kernel subsystem is 17 and entrypoint is hal_init_platform +LDFLAGS = -e hal_init_platform --subsystem=17 --image-base 0x4000000 +LDOBJ = obj/*.obj + +# This file is the Kernel, responsible of task, memory, driver, sci, disk and device management. +KERNEL_IMG = neoskrnl.exe + +.PHONY: error +error: + @echo "=== ERROR ===" + @echo "=> Use a specific target." + +MOVEALL=./MoveAll.X64.sh +WINDRES=x86_64-w64-mingw32-windres + +.PHONY: newos-amd64-epm +newos-amd64-epm: clean + $(WINDRES) KernelRsrc.rsrc -O coff -o KernelRsrc.obj + $(CXX) $(CCFLAGS) $(DISK_DRV) $(DEBUG_MACRO) $(wildcard src/*.cc) $(wildcard HALKit/AMD64/PCI/*.cc) $(wildcard src/Network/*.cc) $(wildcard src/Storage/*.cc) $(wildcard src/FS/*.cc) $(wildcard HALKit/AMD64/Storage/*.cc) $(wildcard HALKit/AMD64/*.cc) $(wildcard src/System/*.cc) $(wildcard HALKit/AMD64/*.s) + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalInterruptAPI.asm + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalCommonAPI.asm + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalBoot.asm + $(ASM) $(ASMFLAGS) HALKit/AMD64/HalUtils.asm + $(MOVEALL) + +OBJCOPY=x86_64-w64-mingw32-objcopy + +.PHONY: link-amd64-epm +link-amd64-epm: + $(LD) $(LDFLAGS) $(LDOBJ) -o $(KERNEL_IMG) + +.PHONY: all +all: newos-amd64-epm link-amd64-epm + @echo "Kernel => OK." + +.PHONY: help +help: + @echo "=== HELP ===" + @echo "all: Build Kernel and link it." + @echo "link-amd64-epm: Link Kernel for EPM based disks." + @echo "newos-amd64-epm: Build Kernel for EPM based disks." + +.PHONY: clean +clean: + rm -f $(LDOBJ) $(wildcard *.o) $(KERNEL_IMG) diff --git a/dev/kernel/arm64-desktop.make b/dev/kernel/arm64-desktop.make new file mode 100644 index 00000000..1b3521d5 --- /dev/null +++ b/dev/kernel/arm64-desktop.make @@ -0,0 +1,64 @@ +################################################## +# (c) Amlal EL Mahrouss, all rights reserved. +# This is the microKernel makefile. +################################################## + +CC = clang++ +LD = lld-link +CCFLAGS = -fshort-wchar -c -ffreestanding -MMD -mno-red-zone -D__NE_ARM64__ -fno-rtti -fno-exceptions -I./ \ + -target aarch64-unknown-windows \ + -std=c++20 -O3 -D__NEOSKRNL__ -D__NE_MINIMAL_OS__ -D__NE_NO_BUILTIN__ -D__HAVE_NE_APIS__ -D__NE__ -I../ + +ASM = clang++ + +DISKDRIVER = -D__USE_FLASH_MEM__ + +ifneq ($(DEBUG_SUPPORT), ) +DEBUG = -D__DEBUG__ +endif + +COPY = cp + +LDFLAGS = -subsystem:efi_application -entry:hal_init_platform /nodefaultlib +LDOBJ = obj/*.obj + +# This file is the Kernel, responsible of task management and memory. +KERNEL = neoskrnl.exe + +.PHONY: error +error: + @echo "=== ERROR ===" + @echo "=> Use a specific target." + +MOVEALL=./MoveAll.ARM64.sh + +.PHONY: newos-arm64-epm +newos-arm64-epm: clean + $(CC) $(CCFLAGS) $(DISKDRIVER) $(DEBUG) $(wildcard src/*.cc) \ + $(wildcard src/FS/*.cc) $(wildcard HALKit/ARM64/Storage/*.cc) \ + $(wildcard HALKit/ARM64/PCI/*.cc) $(wildcard src/Network/*.cc) $(wildcard src/Storage/*.cc) \ + $(wildcard HALKit/ARM64/*.cc) $(wildcard HALKit/ARM64/*.cpp) \ + $(wildcard HALKit/ARM64/*.s) $(wildcard HALKit/ARM64/APM/*.cc) + + $(MOVEALL) + +OBJCOPY=x86_64-w64-mingw32-objcopy + +.PHONY: link-arm64-epm +link-arm64-epm: + $(LD) $(LDFLAGS) $(LDOBJ) /out:$(KERNEL) + +.PHONY: all +all: newos-arm64-epm link-arm64-epm + @echo "Kernel => OK." + +.PHONY: help +help: + @echo "=== HELP ===" + @echo "all: Build Kernel and link it." + @echo "link-arm64-epm: Link Kernel for EPM based disks." + @echo "newos-arm64-epm: Build Kernel for EPM based disks." + +.PHONY: clean +clean: + rm -f $(LDOBJ) $(wildcard *.o) $(KERNEL) diff --git a/dev/kernel/arm64-mobile.make b/dev/kernel/arm64-mobile.make new file mode 100644 index 00000000..1b3521d5 --- /dev/null +++ b/dev/kernel/arm64-mobile.make @@ -0,0 +1,64 @@ +################################################## +# (c) Amlal EL Mahrouss, all rights reserved. +# This is the microKernel makefile. +################################################## + +CC = clang++ +LD = lld-link +CCFLAGS = -fshort-wchar -c -ffreestanding -MMD -mno-red-zone -D__NE_ARM64__ -fno-rtti -fno-exceptions -I./ \ + -target aarch64-unknown-windows \ + -std=c++20 -O3 -D__NEOSKRNL__ -D__NE_MINIMAL_OS__ -D__NE_NO_BUILTIN__ -D__HAVE_NE_APIS__ -D__NE__ -I../ + +ASM = clang++ + +DISKDRIVER = -D__USE_FLASH_MEM__ + +ifneq ($(DEBUG_SUPPORT), ) +DEBUG = -D__DEBUG__ +endif + +COPY = cp + +LDFLAGS = -subsystem:efi_application -entry:hal_init_platform /nodefaultlib +LDOBJ = obj/*.obj + +# This file is the Kernel, responsible of task management and memory. +KERNEL = neoskrnl.exe + +.PHONY: error +error: + @echo "=== ERROR ===" + @echo "=> Use a specific target." + +MOVEALL=./MoveAll.ARM64.sh + +.PHONY: newos-arm64-epm +newos-arm64-epm: clean + $(CC) $(CCFLAGS) $(DISKDRIVER) $(DEBUG) $(wildcard src/*.cc) \ + $(wildcard src/FS/*.cc) $(wildcard HALKit/ARM64/Storage/*.cc) \ + $(wildcard HALKit/ARM64/PCI/*.cc) $(wildcard src/Network/*.cc) $(wildcard src/Storage/*.cc) \ + $(wildcard HALKit/ARM64/*.cc) $(wildcard HALKit/ARM64/*.cpp) \ + $(wildcard HALKit/ARM64/*.s) $(wildcard HALKit/ARM64/APM/*.cc) + + $(MOVEALL) + +OBJCOPY=x86_64-w64-mingw32-objcopy + +.PHONY: link-arm64-epm +link-arm64-epm: + $(LD) $(LDFLAGS) $(LDOBJ) /out:$(KERNEL) + +.PHONY: all +all: newos-arm64-epm link-arm64-epm + @echo "Kernel => OK." + +.PHONY: help +help: + @echo "=== HELP ===" + @echo "all: Build Kernel and link it." + @echo "link-arm64-epm: Link Kernel for EPM based disks." + @echo "newos-arm64-epm: Build Kernel for EPM based disks." + +.PHONY: clean +clean: + rm -f $(LDOBJ) $(wildcard *.o) $(KERNEL) diff --git a/dev/kernel/obj/.hgkeep b/dev/kernel/obj/.hgkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/obj/.hgkeep diff --git a/dev/kernel/power64-cb.make b/dev/kernel/power64-cb.make new file mode 100644 index 00000000..83ab3235 --- /dev/null +++ b/dev/kernel/power64-cb.make @@ -0,0 +1,4 @@ +################################################## +# (c) Amlal EL Mahrouss, all rights reserved. +# This is the microKernel makefile. +################################################## diff --git a/dev/kernel/riscv64-cb.make b/dev/kernel/riscv64-cb.make new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dev/kernel/riscv64-cb.make diff --git a/dev/kernel/src/ACPIFactoryInterface.cc b/dev/kernel/src/ACPIFactoryInterface.cc new file mode 100644 index 00000000..3cc76e44 --- /dev/null +++ b/dev/kernel/src/ACPIFactoryInterface.cc @@ -0,0 +1,101 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <modules/ACPI/ACPIFactoryInterface.h> +#include <NewKit/KString.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/MemoryMgr.h> + +namespace NeOS +{ + /// @brief Finds a descriptor table inside ACPI XSDT. + ErrorOr<voidPtr> ACPIFactoryInterface::Find(const Char* signature) + { + MUST_PASS(this->fRsdp); + + if (!signature) + return ErrorOr<voidPtr>{-1}; + + if (*signature == 0) + return ErrorOr<voidPtr>{-1}; + + RSDP* rsp_ptr = reinterpret_cast<RSDP*>(this->fRsdp); + + if (rsp_ptr->Revision <= 1) + return ErrorOr<voidPtr>{-1}; + + RSDT* xsdt = reinterpret_cast<RSDT*>(rsp_ptr->RsdtAddress); + + Int64 num = (xsdt->Length - sizeof(SDT)) / sizeof(Int64); + + /*** + crucial to avoid underflows. + */ + if (num < 1) + { + /// stop here, we should have entries... + ke_panic(RUNTIME_CHECK_ACPI); + return ErrorOr<voidPtr>{-1}; + } + + this->fEntries = num; + + kout << "ACPI: Number of entries: " << number(this->fEntries) << kendl; + kout << "ACPI: Revision: " << number(xsdt->Revision) << kendl; + kout << "ACPI: Signature: " << xsdt->Signature << kendl; + kout << "ACPI: Address of XSDT: " << hex_number((UIntPtr)xsdt) << kendl; + + const short cAcpiSignatureLength = 4; + + for (Size index = 0; index < this->fEntries; ++index) + { + SDT* sdt = reinterpret_cast<SDT*>(xsdt->AddressArr[index]); + + kout << "ACPI: Checksum: " << number(sdt->Checksum) << kendl; + kout << "ACPI: Revision: " << number(sdt->Revision) << kendl; + + for (short signature_index = 0; signature_index < cAcpiSignatureLength; ++signature_index) + { + if (sdt->Signature[signature_index] != signature[signature_index]) + break; + + if (signature_index == (cAcpiSignatureLength - 1)) + { + kout << "ACPI: SDT Signature: " << sdt->Signature << kendl; + kout << "ACPI: SDT OEM ID: " << sdt->OemId << kendl; + return ErrorOr<voidPtr>(reinterpret_cast<voidPtr>(xsdt->AddressArr[index])); + } + } + } + + return ErrorOr<voidPtr>{-1}; + } + + /*** + @brief Checksum on SDT header. + @param checksum the header to checksum + @param len the length of it. + */ + bool ACPIFactoryInterface::Checksum(const Char* checksum, SSizeT len) + { + if (len == 0) + return 1; + + char chr = 0; + + for (int index = 0; index < len; ++index) + { + chr += checksum[index]; + } + + return chr == 0; + } + + ErrorOr<voidPtr> ACPIFactoryInterface::operator[](const Char* signature) + { + return this->Find(signature); + } +} // namespace NeOS diff --git a/dev/kernel/src/Array.cc b/dev/kernel/src/Array.cc new file mode 100644 index 00000000..29baf162 --- /dev/null +++ b/dev/kernel/src/Array.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Array.h> diff --git a/dev/kernel/src/ArrayList.cc b/dev/kernel/src/ArrayList.cc new file mode 100644 index 00000000..f7221b19 --- /dev/null +++ b/dev/kernel/src/ArrayList.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/ArrayList.h> diff --git a/dev/kernel/src/Atom.cc b/dev/kernel/src/Atom.cc new file mode 100644 index 00000000..92620c27 --- /dev/null +++ b/dev/kernel/src/Atom.cc @@ -0,0 +1,10 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Atom.h> + +// @file Atom.cpp +// @brief Atomic primitives diff --git a/dev/kernel/src/BinaryMutex.cc b/dev/kernel/src/BinaryMutex.cc new file mode 100644 index 00000000..4fdaa8f4 --- /dev/null +++ b/dev/kernel/src/BinaryMutex.cc @@ -0,0 +1,74 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/BinaryMutex.h> + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Unlocks the semaphore. + /***********************************************************************************/ + Bool BinaryMutex::Unlock() noexcept + { + if (fLockingProcess) + { + fLockingProcess = UserProcess(); + fLockingProcess.Status = ProcessStatusKind::kFrozen; + return Yes; + } + + return No; + } + + /***********************************************************************************/ + /// @brief Locks process in the semaphore. + /***********************************************************************************/ + Bool BinaryMutex::Lock(UserProcess& process) + { + if (!process || fLockingProcess) + return No; + + fLockingProcess = process; + + return Yes; + } + + /***********************************************************************************/ + /// @brief Checks if process is locked. + /***********************************************************************************/ + Bool BinaryMutex::IsLocked() const + { + return fLockingProcess.Status == ProcessStatusKind::kRunning; + } + + /***********************************************************************************/ + /// @brief Try lock or wait. + /***********************************************************************************/ + Bool BinaryMutex::LockOrWait(UserProcess& process, TimerInterface* timer) + { + if (timer == nullptr) + return No; + + this->Lock(process); + + timer->Wait(); + + return this->Lock(process); + } + + /***********************************************************************************/ + /// @brief Wait for process **sec** until we check if it's free. + /// @param sec seconds. + /***********************************************************************************/ + BOOL BinaryMutex::WaitForProcess(const Int16& sec) noexcept + { + HardwareTimer hw_timer(rtl_seconds(sec)); + hw_timer.Wait(); + + return !this->IsLocked(); + } +} // namespace NeOS diff --git a/dev/kernel/src/BitMapMgr.cc b/dev/kernel/src/BitMapMgr.cc new file mode 100644 index 00000000..18b1a156 --- /dev/null +++ b/dev/kernel/src/BitMapMgr.cc @@ -0,0 +1,195 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> + +#ifdef __NE_AMD64__ +#include <HALKit/AMD64/Paging.h> +#elif defined(__NE_ARM64__) +#include <HALKit/ARM64/Paging.h> +#endif + +#include <NewKit/Defines.h> +#include <NewKit/KernelPanic.h> + +#define kBitMapMagic (0x10210U) +#define kBitMapPadSize (mib_cast(16)) + +#define kBitMapMagIdx (0U) +#define kBitMapSizeIdx (1U) +#define kBitMapUsedIdx (2U) + +namespace NeOS +{ + namespace HAL + { + namespace Detail + { + /// \brief Proxy Interface to allocate a bitmap. + class IBitMapProxy final + { + public: + explicit IBitMapProxy() = default; + ~IBitMapProxy() = default; + + NE_COPY_DELETE(IBitMapProxy); + + auto IsBitMap(VoidPtr page_ptr) -> Bool + { + if (!page_ptr) + return No; + + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(page_ptr); + + if (!ptr_bit_set[kBitMapMagIdx] || + ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) + return No; + + return Yes; + } + + auto FreeBitMap(VoidPtr page_ptr) -> Bool + { + if (this->IsBitMap(page_ptr) == No) + return No; + + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(page_ptr); + + ptr_bit_set[kBitMapMagIdx] = kBitMapMagic; + ptr_bit_set[kBitMapUsedIdx] = No; + + this->GetBitMapStatus(ptr_bit_set); + + return Yes; + } + + UInt32 MakeMMFlags(Bool wr, Bool user) + { + UInt32 flags = kMMFlagsPresent; + + if (wr) + flags |= kMMFlagsWr; + + if (user) + flags |= kMMFlagsUser; + + return flags; + } + + /// @brief Iterate over availables pages for a free one. + /// @return The new address which was found. + auto FindBitMap(VoidPtr base_ptr, SizeT size, Bool wr, Bool user) -> VoidPtr + { + if (!size) + return nullptr; + + VoidPtr base = reinterpret_cast<VoidPtr>(((UIntPtr)base_ptr) + kPageSize); + + static SizeT biggest_block = 0UL; + + while (YES) + { + UIntPtr* ptr_bit_set = reinterpret_cast<UIntPtr*>(base); + + if (ptr_bit_set[kBitMapMagIdx] == kBitMapMagic && + ptr_bit_set[kBitMapSizeIdx] == size) + { + if (ptr_bit_set[kBitMapUsedIdx] == No) + { + ptr_bit_set[kBitMapSizeIdx] = size; + ptr_bit_set[kBitMapUsedIdx] = Yes; + + this->GetBitMapStatus(ptr_bit_set); + + UInt32 flags = this->MakeMMFlags(wr, user); + mm_map_page(ptr_bit_set, ptr_bit_set, flags); + + if (biggest_block < size) + biggest_block = size; + + return (VoidPtr)ptr_bit_set; + } + } + else if (ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) + { + ptr_bit_set[kBitMapMagIdx] = kBitMapMagic; + ptr_bit_set[kBitMapSizeIdx] = size; + ptr_bit_set[kBitMapUsedIdx] = Yes; + + this->GetBitMapStatus(ptr_bit_set); + + UInt32 flags = this->MakeMMFlags(wr, user); + mm_map_page(ptr_bit_set, ptr_bit_set, flags); + + if (biggest_block < size) + biggest_block = size; + + return (VoidPtr)ptr_bit_set; + } + + base = reinterpret_cast<VoidPtr>(reinterpret_cast<UIntPtr>(base) + ((ptr_bit_set[kBitMapMagIdx] != kBitMapMagic) ? (size) : ptr_bit_set[kBitMapSizeIdx])); + } + + return nullptr; + } + + /// @brief Print Bitmap status + auto GetBitMapStatus(UIntPtr* ptr_bit_set) -> Void + { + if (!this->IsBitMap(ptr_bit_set)) + { + kout << "Not a BitMap: " << hex_number((UIntPtr)ptr_bit_set) << kendl; + return; + } + + kout << "Magic Number: " << hex_number(ptr_bit_set[kBitMapMagIdx]) << kendl; + kout << "Is Allocated: " << (ptr_bit_set[kBitMapUsedIdx] ? "Yes" : "No") << kendl; + kout << "Size of BitMap (B): " << number(ptr_bit_set[kBitMapSizeIdx]) << kendl; + kout << "Size of BitMap (KIB): " << number(KIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Size of BitMap (MIB): " << number(MIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Size of BitMap (GIB): " << number(GIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Size of BitMap (TIB): " << number(TIB(ptr_bit_set[kBitMapSizeIdx])) << kendl; + kout << "Address Of BitMap Header: " << hex_number((UIntPtr)ptr_bit_set) << kendl; + } + }; + } // namespace Detail + + auto mm_is_bitmap(VoidPtr ptr) -> Bool + { + Detail::IBitMapProxy bitmp; + return bitmp.IsBitMap(ptr); + } + + /// @brief Allocate a new page to be used by the OS. + /// @param wr read/write bit. + /// @param user user bit. + /// @return a new bitmap allocated pointer. + auto mm_alloc_bitmap(Boolean wr, Boolean user, SizeT size, Bool is_page) -> VoidPtr + { + VoidPtr ptr_new = nullptr; + Detail::IBitMapProxy bitmp; + + ptr_new = bitmp.FindBitMap(kKernelBitMpStart, size, wr, user); + + MUST_PASS(ptr_new); + + return (UIntPtr*)ptr_new; + } + + /// @brief Free Bitmap, and mark it as absent. + /// @param ptr the pointer to free. + auto mm_free_bitmap(VoidPtr ptr) -> Bool + { + if (!ptr) + return No; + + Detail::IBitMapProxy bitmp; + Bool ret = bitmp.FreeBitMap(ptr); + + return ret; + } + } // namespace HAL +} // namespace NeOS diff --git a/dev/kernel/src/CodeMgr.cc b/dev/kernel/src/CodeMgr.cc new file mode 100644 index 00000000..c639155d --- /dev/null +++ b/dev/kernel/src/CodeMgr.cc @@ -0,0 +1,28 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/CodeMgr.h> +#include <NewKit/Utils.h> +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Executes a new process from a function. Kernel code only. + /// @note This sets up a new stack, anything on the main function that calls the Kernel will not be accessible. + /// @param main the start of the process. + /// @return if the process was started or not. + /***********************************************************************************/ + + ProcessID rtl_create_process(rtl_main_kind main, const Char* process_name) noexcept + { + if (!process_name || + *process_name == 0) + return kProcessInvalidID; + + return UserProcessScheduler::The().Spawn(process_name, reinterpret_cast<VoidPtr>(main), nullptr); + } +} // namespace NeOS diff --git a/dev/kernel/src/Crc32.cc b/dev/kernel/src/Crc32.cc new file mode 100644 index 00000000..98821602 --- /dev/null +++ b/dev/kernel/src/Crc32.cc @@ -0,0 +1,82 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Crc32.h> + +// @file CRC32.cpp +// @brief Check sequence implementation. + +namespace NeOS +{ + /// @brief The CRC32 seed table. + UInt32 kCrcTbl[kCrcCnt] = { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, + 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, + 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, + 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, + 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, + 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, + 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, + 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, + 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, + 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, + 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, + 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, + 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, + 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, + 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, + 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, + 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, + 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, + 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, + 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, + 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, + 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, + 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, + 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, + 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, + 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, + 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, + 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, + 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, + 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, + 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, + 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, + 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, + 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, + 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, + 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, + 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, + 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, + 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, + 0xAD7D5351L}; + + /// @brief Calculate CRC32 of p + /// @param p the data to compute. + /// @param len the length of the data. + /// @return CRC32 of **p**. + UInt32 ke_calculate_crc32(const Char* p, Int32 len) noexcept + { + UInt32 crc = 0xffffffff; + + while (--len > 0) + crc = kCrcTbl[((UInt8)crc ^ *(p++))] ^ (crc >> 8); + + return ~crc; + } +} // namespace NeOS diff --git a/dev/kernel/src/CxxAbi-AMD64.cc b/dev/kernel/src/CxxAbi-AMD64.cc new file mode 100644 index 00000000..f0e57077 --- /dev/null +++ b/dev/kernel/src/CxxAbi-AMD64.cc @@ -0,0 +1,90 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __NE_AMD64__ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/CxxAbi.h> +#include <KernelKit/LPC.h> + +atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; + +uarch_t __atexit_func_count; + +/// @brief dynamic shared object Handle. +NeOS::UIntPtr __dso_handle; + +EXTERN_C NeOS::Void __cxa_pure_virtual(void* self) +{ + kout << "object: " << NeOS::number(reinterpret_cast<NeOS::UIntPtr>(self)); + kout << ", has unimplemented virtual functions.\r"; +} + +EXTERN_C void ___chkstk_ms(void) +{ +} + +EXTERN_C int atexit(void (*f)(void*), void* arg, void* dso) +{ + if (__atexit_func_count >= kAtExitMacDestructors) + return 1; + + __atexit_funcs[__atexit_func_count].destructor_func = f; + __atexit_funcs[__atexit_func_count].obj_ptr = arg; + __atexit_funcs[__atexit_func_count].dso_handle = dso; + + __atexit_func_count++; + + return 0; +} + +EXTERN_C void __cxa_finalize(void* f) +{ + uarch_t i = __atexit_func_count; + if (!f) + { + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + }; + } + + return; + } + + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + __atexit_funcs[i].destructor_func = 0; + }; + } +} + +namespace cxxabiv1 +{ + EXTERN_C int __cxa_guard_acquire(__guard* g) + { + (void)g; + return 0; + } + + EXTERN_C int __cxa_guard_release(__guard* g) + { + *(char*)g = 1; + return 0; + } + + EXTERN_C void __cxa_guard_abort(__guard* g) + { + (void)g; + } +} // namespace cxxabiv1 + +#endif // ifdef __NE_AMD64__ diff --git a/dev/kernel/src/CxxAbi-ARM64.cc b/dev/kernel/src/CxxAbi-ARM64.cc new file mode 100644 index 00000000..b52be160 --- /dev/null +++ b/dev/kernel/src/CxxAbi-ARM64.cc @@ -0,0 +1,107 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __NE_ARM64__ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/CxxAbi.h> +#include <KernelKit/LPC.h> + +atexit_func_entry_t __atexit_funcs[kAtExitMacDestructors]; + +uarch_t __atexit_func_count; + +/// @brief dynamic shared object Handle. +NeOS::UIntPtr __dso_handle; + +EXTERN_C void __chkstk(void) +{ +} + +EXTERN_C int atexit(void (*f)(void*), void* arg, void* dso) +{ + if (__atexit_func_count >= kAtExitMacDestructors) + return 1; + + __atexit_funcs[__atexit_func_count].destructor_func = f; + __atexit_funcs[__atexit_func_count].obj_ptr = arg; + __atexit_funcs[__atexit_func_count].dso_handle = dso; + + __atexit_func_count++; + + return 0; +} + +EXTERN_C void __cxa_finalize(void* f) +{ + uarch_t i = __atexit_func_count; + if (!f) + { + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + }; + } + + return; + } + + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + __atexit_funcs[i].destructor_func = 0; + }; + } +} + +namespace cxxabiv1 +{ + EXTERN_C int __cxa_guard_acquire(__guard* g) + { + (void)g; + return 0; + } + + EXTERN_C int __cxa_guard_release(__guard* g) + { + *(char*)g = 1; + return 0; + } + + EXTERN_C void __cxa_guard_abort(__guard* g) + { + (void)g; + } +} // namespace cxxabiv1 + +EXTERN_C NeOS::Void _purecall(void* self) +{ + kout << "object: " << NeOS::number(reinterpret_cast<NeOS::UIntPtr>(self)); + kout << ", has unimplemented virtual functions.\r"; +} + +EXTERN_C NeOS::Void _Init_thread_footer(NeOS::Int* thread_obj) +{ + NE_UNUSED(thread_obj); +} + +EXTERN_C NeOS::Void _Init_thread_epoch(NeOS::Void) +{ + NE_UNUSED(0); +} + +EXTERN_C NeOS::Void _Init_thread_header(NeOS::Int* thread_obj) +{ + NE_UNUSED(0); +} + +EXTERN_C NeOS::Int _tls_index = 0UL; + +#endif // ifdef __NE_ARM64__ diff --git a/dev/kernel/src/Defines.cc b/dev/kernel/src/Defines.cc new file mode 100644 index 00000000..c29afcf4 --- /dev/null +++ b/dev/kernel/src/Defines.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Defines.h> diff --git a/dev/kernel/src/DeviceMgr.cc b/dev/kernel/src/DeviceMgr.cc new file mode 100644 index 00000000..760d17d9 --- /dev/null +++ b/dev/kernel/src/DeviceMgr.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DeviceMgr.h> diff --git a/dev/kernel/src/DriveMgr+IO.cc b/dev/kernel/src/DriveMgr+IO.cc new file mode 100644 index 00000000..8381087f --- /dev/null +++ b/dev/kernel/src/DriveMgr+IO.cc @@ -0,0 +1,96 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DriveMgr.h> +#include <KernelKit/FileMgr.h> + +/************************************************************* + * + * File: DriveMgr+IO.cc + * Purpose: Filesystem to mountpoint interface. + * Date: 3/26/24 + * + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + *************************************************************/ + +/// Useful macros. + +#define rtl_nefs_write(DRV, TRAITS, MP) (MP->DRV()).fOutput(TRAITS) +#define rtl_nefs_read(DRV, TRAITS, MP) (MP->DRV()).fInput(TRAITS) + +namespace NeOS +{ + /// @brief Read from newfs disk. + /// @param Mnt mounted interface. + /// @param DrvTrait drive info + /// @param DrvIndex drive index. + /// @return + Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) + { + if (!Mnt) + return 1; + + DrvTrait.fPacket.fPacketGood = false; + + switch (DrvIndex) + { + case MountpointInterface::kDriveIndexA: { + rtl_nefs_read(A, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexB: { + rtl_nefs_read(B, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexC: { + rtl_nefs_read(C, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexD: { + rtl_nefs_read(D, DrvTrait.fPacket, Mnt); + break; + } + } + + return DrvTrait.fPacket.fPacketGood; + } + + /// @brief Write to newfs disk. + /// @param Mnt mounted interface. + /// @param DrvTrait drive info + /// @param DrvIndex drive index. + /// @return + Int32 fs_ifs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) + { + if (!Mnt) + return 1; + + DrvTrait.fPacket.fPacketGood = false; + + switch (DrvIndex) + { + case MountpointInterface::kDriveIndexA: { + rtl_nefs_write(A, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexB: { + rtl_nefs_write(B, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexC: { + rtl_nefs_write(C, DrvTrait.fPacket, Mnt); + break; + } + case MountpointInterface::kDriveIndexD: { + rtl_nefs_write(D, DrvTrait.fPacket, Mnt); + break; + } + } + + return DrvTrait.fPacket.fPacketGood; + } +} // namespace NeOS
\ No newline at end of file diff --git a/dev/kernel/src/DriveMgr.cc b/dev/kernel/src/DriveMgr.cc new file mode 100644 index 00000000..039f7e08 --- /dev/null +++ b/dev/kernel/src/DriveMgr.cc @@ -0,0 +1,235 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/DriveMgr.h> +#include <NewKit/Utils.h> +#include <FirmwareKit/EPM.h> +#include <modules/ATA/ATA.h> +#include <modules/AHCI/AHCI.h> +#include <modules/NVME/NVME.h> + +/***********************************************************************************/ +/// @file DriveMgr.cc +/// @brief Drive Manager of kernel. +/***********************************************************************************/ + +namespace NeOS +{ +#if defined(__ATA_PIO__) || defined(__ATA_DMA__) + STATIC UInt16 kATAIO = 0U; + STATIC UInt8 kATAMaster = 0U; +#endif + +#if defined(__AHCI__) + STATIC UInt16 kAHCIPortsImplemented = 0UL; +#endif + + /// @brief reads from an ATA drive. + /// @param pckt Packet structure (fPacketContent must be non null) + /// @return + Void io_drv_input(DriveTrait::DrivePacket pckt) + { +#ifdef __AHCI__ + drv_std_read(pckt.fPacketLba, (Char*)pckt.fPacketContent, kAHCISectorSize, pckt.fPacketSize); +#elif defined(__ATA_PIO__) || defined(__ATA_DMA__) + drv_std_read(pckt.fPacketLba, kATAIO, kATAMaster, (Char*)pckt.fPacketContent, kATASectorSize, pckt.fPacketSize); +#endif + } + + /// @brief Writes to an ATA drive. + /// @param pckt the packet to write. + /// @return + Void io_drv_output(DriveTrait::DrivePacket pckt) + { + if (pckt.fPacketReadOnly) + { + pckt.fPacketGood = NO; + return; + } + +#ifdef __AHCI__ + drv_std_write(pckt.fPacketLba, (Char*)pckt.fPacketContent, kAHCISectorSize, pckt.fPacketSize); +#elif defined(__ATA_PIO__) || defined(__ATA_DMA__) + drv_std_write(pckt.fPacketLba, kATAIO, kATAMaster, (Char*)pckt.fPacketContent, kATASectorSize, pckt.fPacketSize); +#endif + } + + /// @brief Executes a disk check on the ATA drive. + /// @param pckt the packet to read. + /// @return + Void io_drv_init(DriveTrait::DrivePacket pckt) + { +#if defined(__ATA_PIO__) || defined(__ATA_DMA__) + kATAMaster = 0; + kATAIO = 0; + + kATAMaster = YES; + kATAIO = ATA_PRIMARY_IO; + + if (drv_std_init(kATAIO, kATAMaster, kATAIO, kATAMaster)) + { + pckt.fPacketGood = YES; + return; + } + + kATAMaster = NO; + kATAIO = ATA_SECONDARY_IO; + + if (!drv_std_init(kATAIO, kATAMaster, kATAIO, kATAMaster)) + { + pckt.fPacketGood = YES; + return; + } + + pckt.fPacketGood = YES; +#elif defined(__AHCI__) + kAHCIPortsImplemented = 0; + + if (!drv_std_init(kAHCIPortsImplemented)) + { + return; + } + + pckt.fPacketGood = YES; +#endif // if defined(__ATA_PIO__) || defined (__ATA_DMA__) + } + +/// @brief Gets the drive kind (ATA, SCSI, AHCI...) +/// @param void no arguments. +/// @return no arguments. +#ifdef __ATA_PIO__ + const Char* io_drv_kind(Void) + { + return "ATA-PIO"; + } +#endif +#ifdef __ATA_DMA__ + const Char* io_drv_kind(Void) + { + return "ATA-DMA"; + } +#endif +#ifdef __AHCI__ + const Char* io_drv_kind(Void) + { + return "AHCI"; + } +#endif +#ifdef __NE_MINIMAL_OS__ + const Char* io_drv_kind(Void) + { + return "Not Loaded"; + } +#endif + + /// @brief Unimplemented drive function. + /// @param pckt the packet to read. + Void io_drv_unimplemented(DriveTrait::DrivePacket pckt) noexcept + { + NE_UNUSED(pckt); + } + + /// @brief Makes a new drive. + /// @return the new blank drive. + DriveTrait io_construct_blank_drive() noexcept + { + DriveTrait trait; + + constexpr auto kBlankDrive = "/media/blank/"; + + rt_copy_memory((VoidPtr)kBlankDrive, trait.fName, rt_string_len(kBlankDrive)); + trait.fKind = kInvalidDrive; + + trait.fInput = io_drv_unimplemented; + trait.fOutput = io_drv_unimplemented; + trait.fVerify = io_drv_unimplemented; + trait.fInit = io_drv_unimplemented; + trait.fDriveKind = io_drv_kind; + + kout << "Construct: " << trait.fName << "\r"; + + return trait; + } + + namespace Detail + { + Void io_detect_drive(DriveTrait& trait) + { + trait.fInit(trait.fPacket); + + EPM_PART_BLOCK block_struct; + + trait.fPacket.fPacketLba = kEPMBootBlockLba; + trait.fPacket.fPacketSize = sizeof(EPM_PART_BLOCK); + trait.fPacket.fPacketContent = &block_struct; + + rt_copy_memory((VoidPtr) "fs/detect-packet", trait.fPacket.fPacketMime, + rt_string_len("fs/detect-packet")); + + trait.fInput(trait.fPacket); + + if (rt_string_cmp(((EPM_PART_BLOCK*)trait.fPacket.fPacketContent)->Magic, kEPMMagic, kEPMMagicLength) == 0) + { + trait.fPacket.fPacketReadOnly = NO; + trait.fKind = kMassStorageDrive | kEPMDrive; + + kout << "Disk is EPM.\r"; + + trait.fSectorSz = block_struct.SectorSz; + trait.fLbaEnd = block_struct.LbaEnd; + trait.fLbaStart = block_struct.LbaStart; + } + else + { + trait.fPacket.fPacketReadOnly = YES; + trait.fKind = kMassStorageDrive | kUnformattedDrive | kReadOnlyDrive; + + if (block_struct.Name[0] == 0 || + !rt_is_alnum(block_struct.Name[0])) + { + kout << "Disk partition is empty (Read Only)\r"; + } + else + { + kout << "Scheme Found: " << block_struct.Name << kendl; + } + } + + rt_copy_memory((VoidPtr) "*/*", trait.fPacket.fPacketMime, + rt_string_len("*/*")); + + trait.fPacket.fPacketLba = 0; + trait.fPacket.fPacketSize = 0UL; + trait.fPacket.fPacketContent = nullptr; + } + } // namespace Detail + + /// @brief Fetches the main drive. + /// @return the new drive. (returns kEPMDrive if EPM formatted) + DriveTrait io_construct_main_drive() noexcept + { + DriveTrait trait; + + constexpr auto kMainDrive = "/media/sda/"; + + rt_copy_memory((VoidPtr)kMainDrive, trait.fName, rt_string_len(kMainDrive)); + + MUST_PASS(trait.fName[0] != 0); + + trait.fVerify = io_drv_unimplemented; + trait.fOutput = io_drv_output; + trait.fInput = io_drv_input; + trait.fInit = io_drv_init; + trait.fDriveKind = io_drv_kind; + + kout << "Detecting partition scheme of: " << trait.fName << ".\r"; + + Detail::io_detect_drive(trait); + + return trait; + } +} // namespace NeOS diff --git a/dev/kernel/src/ErrorOr.cc b/dev/kernel/src/ErrorOr.cc new file mode 100644 index 00000000..7a55715c --- /dev/null +++ b/dev/kernel/src/ErrorOr.cc @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/ErrorOr.h> + +/***********************************************************************************/ +/// @file ErrorOr.cc /// +/// @brief ErrorOr container class. /// +/***********************************************************************************/ diff --git a/dev/kernel/src/FS/HeFS.cc b/dev/kernel/src/FS/HeFS.cc new file mode 100644 index 00000000..7615ed77 --- /dev/null +++ b/dev/kernel/src/FS/HeFS.cc @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __FSKIT_INCLUDES_HeFS__ + +#include <modules/AHCI/AHCI.h> +#include <modules/ATA/ATA.h> +#include <modules/Flash/Flash.h> +#include <FSKit/HeFS.h> +#include <KernelKit/LPC.h> +#include <NewKit/Crc32.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/KString.h> +#include <NewKit/Utils.h> +#include <FirmwareKit/EPM.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/User.h> + +#endif // ifdef __FSKIT_INCLUDES_HeFS__ diff --git a/dev/kernel/src/FS/NeFS+FileMgr.cc b/dev/kernel/src/FS/NeFS+FileMgr.cc new file mode 100644 index 00000000..0ac6384d --- /dev/null +++ b/dev/kernel/src/FS/NeFS+FileMgr.cc @@ -0,0 +1,245 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/FileMgr.h> +#include <KernelKit/MemoryMgr.h> + +#ifndef __NE_MINIMAL_OS__ +#ifdef __FSKIT_INCLUDES_NEFS__ + +/// @brief NeFS File manager. +/// BUGS: 0 + +namespace NeOS +{ + /// @brief C++ constructor + NeFileSystemMgr::NeFileSystemMgr() + { + NeFileSystemParser* mParser = new NeFileSystemParser(); + MUST_PASS(mParser); + + kout << "We are done allocating NeFileSystemParser...\r"; + } + + NeFileSystemMgr::~NeFileSystemMgr() + { + if (mParser) + { + kout << "Destroying NeFileSystemParser...\r"; + mm_delete_class(&mParser); + } + } + + /// @brief Removes a node from the filesystem. + /// @param path The filename + /// @return If it was deleted or not. + bool NeFileSystemMgr::Remove(_Input const Char* path) + { + if (path == nullptr || *path == 0) + return false; + + return mParser->RemoveCatalog(path); + } + + /// @brief Creates a node with the specified. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::Create(_Input const Char* path) + { + return node_cast(mParser->CreateCatalog(path)); + } + + /// @brief Creates a node with is a directory. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::CreateDirectory(const Char* path) + { + return node_cast(mParser->CreateCatalog(path, 0, kNeFSCatalogKindDir)); + } + + /// @brief Creates a node with is a alias. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::CreateAlias(const Char* path) + { + return node_cast(mParser->CreateCatalog(path, 0, kNeFSCatalogKindAlias)); + } + + /// @brief Creates a node with is a page file. + /// @param path The filename path. + /// @return The Node pointer. + NodePtr NeFileSystemMgr::CreateSwapFile(const Char* path) + { + return node_cast(mParser->CreateCatalog(path, 0, kNeFSCatalogKindPage)); + } + + /// @brief Gets the root directory. + /// @return + const Char* NeFileSystemHelper::Root() + { + return kNeFSRoot; + } + + /// @brief Gets the up-dir directory. + /// @return + const Char* NeFileSystemHelper::UpDir() + { + return kNeFSUpDir; + } + + /// @brief Gets the separator character. + /// @return + const Char NeFileSystemHelper::Separator() + { + return kNeFSSeparator; + } + + /// @brief Gets the metafile character. + /// @return + const Char NeFileSystemHelper::MetaFile() + { + return kNeFSMetaFilePrefix; + } + + /// @brief Opens a new file. + /// @param path + /// @param r + /// @return + _Output NodePtr NeFileSystemMgr::Open(_Input const Char* path, _Input const Char* r) + { + if (!path || *path == 0) + return nullptr; + + if (!r || *r == 0) + return nullptr; + + auto catalog = mParser->GetCatalog(path); + + return node_cast(catalog); + } + + /// @brief Writes to a catalog's fork. + /// @param node the node ptr. + /// @param data the data. + /// @param flags the size. + /// @return + Void NeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, _Input SizeT size) + { + if (!node) + return; + if (!size) + return; + + constexpr auto kDataForkName = kNeFSDataFork; + this->Write(kDataForkName, node, data, flags, size); + } + + /// @brief Read from filesystem fork. + /// @param node the catalog node. + /// @param flags the flags with it. + /// @param sz the size to read. + /// @return + _Output VoidPtr NeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) + { + if (!node) + return nullptr; + if (!size) + return nullptr; + + constexpr auto kDataForkName = kNeFSDataFork; + return this->Read(kDataForkName, node, flags, size); + } + + Void NeFileSystemMgr::Write(_Input const Char* name, + _Input NodePtr node, + _Input VoidPtr data, + _Input Int32 flags, + _Input SizeT size) + { + if (!size || + size > kNeFSForkSize) + return; + + if (!data) + return; + + NE_UNUSED(flags); + + if ((reinterpret_cast<NEFS_CATALOG_STRUCT*>(node))->Kind == kNeFSCatalogKindFile) + mParser->WriteCatalog(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node)->Name, (flags & kFileFlagRsrc ? true : false), data, size, + name); + } + + _Output VoidPtr NeFileSystemMgr::Read(_Input const Char* name, + _Input NodePtr node, + _Input Int32 flags, + _Input SizeT sz) + { + if (sz > kNeFSForkSize) + return nullptr; + + if (!sz) + return nullptr; + + NE_UNUSED(flags); + + if ((reinterpret_cast<NEFS_CATALOG_STRUCT*>(node))->Kind == kNeFSCatalogKindFile) + return mParser->ReadCatalog(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node), (flags & kFileFlagRsrc ? true : false), sz, + name); + + return nullptr; + } + + /// @brief Seek from Catalog. + /// @param node + /// @param off + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output Bool NeFileSystemMgr::Seek(NodePtr node, SizeT off) + { + if (!node || off == 0) + return false; + + return mParser->Seek(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node), off); + } + + /// @brief Tell where the catalog is. + /// @param node + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output SizeT NeFileSystemMgr::Tell(NodePtr node) + { + if (!node) + return kNPos; + + return mParser->Tell(reinterpret_cast<NEFS_CATALOG_STRUCT*>(node)); + } + + /// @brief Rewinds the catalog. + /// @param node + /// @retval true always returns false, this is unimplemented. + /// @retval false always returns this, it is unimplemented. + + _Output Bool NeFileSystemMgr::Rewind(NodePtr node) + { + if (!node) + return false; + + return this->Seek(node, 0); + } + + /// @brief Returns the filesystem parser. + /// @return the Filesystem parser class. + _Output NeFileSystemParser* NeFileSystemMgr::GetParser() noexcept + { + return mParser; + } +} // namespace NeOS + +#endif // ifdef __FSKIT_INCLUDES_NEFS__ +#endif // ifndef __NE_MINIMAL_OS__ diff --git a/dev/kernel/src/FS/NeFS.cc b/dev/kernel/src/FS/NeFS.cc new file mode 100644 index 00000000..30d4fb85 --- /dev/null +++ b/dev/kernel/src/FS/NeFS.cc @@ -0,0 +1,1065 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __FSKIT_INCLUDES_NEFS__ + +#include <FSKit/NeFS.h> +#include <FirmwareKit/EPM.h> + +#include <modules/AHCI/AHCI.h> +#include <modules/ATA/ATA.h> +#include <modules/MFlash/MFlash.h> +#include <KernelKit/LPC.h> +#include <NewKit/Crc32.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/KString.h> +#include <NewKit/Utils.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/User.h> +#include <KernelKit/DriveMgr.h> + +using namespace NeOS; + +#ifdef __NE_NO_BUILTIN__ +/***********************************************************************************/ +/** + Define those external symbols, to make the editor shutup +*/ +/***********************************************************************************/ + +/***********************************************************************************/ +/// @brief get sector count. +/***********************************************************************************/ +NeOS::SizeT drv_get_sector_count(); + +/***********************************************************************************/ +/// @brief get device size. +/***********************************************************************************/ +NeOS::SizeT drv_get_size(); + +#endif + +///! BUGS: 0 + +/***********************************************************************************/ +/// This file implements the New extended File System. +/// New extended File System implements a B-Tree based algortihm. +/// / +/// /Path1/ /ath2/ +/// /readme.rtf /ListContents.pef /readme.lnk <-- symlink. +/// /Path1/readme.rtf +/***********************************************************************************/ + +STATIC MountpointInterface kMountpoint; + +/***********************************************************************************/ +/// @brief Creates a new fork inside the New filesystem partition. +/// @param catalog it's catalog +/// @param the_fork the fork itself. +/// @return the fork +/***********************************************************************************/ +_Output BOOL NeFileSystemParser::CreateFork(_Input NEFS_FORK_STRUCT& the_fork) +{ + if (the_fork.ForkName[0] != 0 && + the_fork.CatalogName[0] != 0 && + the_fork.DataSize > 0) + { + auto catalog = this->GetCatalog(the_fork.CatalogName); + + if (!catalog) + return NO; + + Lba lba = catalog->DataFork; + + kout << "Fork LBA: " << hex_number(lba) << kendl; + + if (lba < kNeFSCatalogStartAddress) + return NO; + + auto& drv = kMountpoint.A(); + + Lba lba_prev = lba; + + NEFS_FORK_STRUCT prev_fork; + NEFS_FORK_STRUCT cur_fork; + + /// do not check for anything. Loop until we get what we want, that is a free fork zone. + while (drv.fPacket.fPacketGood) + { + drv.fPacket.fPacketLba = lba; + drv.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &cur_fork; + + drv.fInput(drv.fPacket); + + kout << "Next fork: " << hex_number(cur_fork.NextSibling) << kendl; + + if (cur_fork.Flags & kNeFSFlagCreated) + { + kout << "Error: Fork does exists.\r"; + + /// sanity check. + if (KStringBuilder::Equals(cur_fork.ForkName, the_fork.ForkName) && + KStringBuilder::Equals(cur_fork.CatalogName, the_fork.CatalogName)) + break; + + lba_prev = lba; + lba = cur_fork.NextSibling; + + prev_fork = cur_fork; + } + else + { + /// This is a check that we have, in order to link the previous fork + /// entry. + if (lba >= kNeFSCatalogStartAddress) + { + drv.fPacket.fPacketLba = lba_prev; + drv.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &prev_fork; + + prev_fork.NextSibling = lba; + + /// write to disk. + drv.fOutput(drv.fPacket); + } + + break; + } + } + + the_fork.Flags |= kNeFSFlagCreated; + the_fork.DataOffset = lba - sizeof(NEFS_FORK_STRUCT); + the_fork.PreviousSibling = lba_prev; + the_fork.NextSibling = the_fork.DataOffset - the_fork.DataSize; + + drv.fPacket.fPacketLba = lba; + drv.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drv.fPacket.fPacketContent = &the_fork; + + kout << "Allocating fork block...\r"; + + // drv.fOutput(drv.fPacket); + + fs_ifs_write(&kMountpoint, drv, MountpointInterface::kDriveIndexA); + + /// log what we have now. + kout << "Fork offset is at: " << hex_number(the_fork.DataOffset) + << kendl; + + kout << "Wrote fork metadata at: " << hex_number(lba) << kendl; + + return YES; + } + + return NO; +} + +/***********************************************************************************/ +/// @brief Find fork inside filesystem. +/// @param catalog the catalog. +/// @param name the fork name. +/// @return the newly found fork. +/***********************************************************************************/ +_Output NEFS_FORK_STRUCT* NeFileSystemParser::FindFork(_Input NEFS_CATALOG_STRUCT* catalog, + _Input const Char* name, + _Input Boolean is_data) +{ + auto& drive = kMountpoint.A(); + NEFS_FORK_STRUCT* the_fork = nullptr; + + Lba lba = is_data ? catalog->DataFork : catalog->ResourceFork; + + while (lba != 0) + { + drive.fPacket.fPacketLba = lba; + drive.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drive.fPacket.fPacketContent = (VoidPtr)the_fork; + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, 16); + + if (auto res = + fs_ifs_read(&kMountpoint, drive, this->mDriveIndex); + res) + { + switch (res) + { + case 1: + err_global_get() = kErrorDiskReadOnly; + break; + case 2: + err_global_get() = kErrorDiskIsFull; + break; + case 3: + err_global_get() = kErrorNoSuchDisk; + break; + + default: + break; + } + return nullptr; + } + + if (KStringBuilder::Equals(the_fork->ForkName, name)) + { + break; + } + + lba = the_fork->NextSibling; + } + + return the_fork; +} + +/***********************************************************************************/ +/// @brief Simpler factory to create a catalog (assumes you want to create a +/// file.) +/// @param name +/// @return catalog pointer. +/***********************************************************************************/ +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::CreateCatalog(_Input const Char* name) +{ + return this->CreateCatalog(name, 0, kNeFSCatalogKindFile); +} + +/***********************************************************************************/ +/// @brief Creates a new catalog into the disk. +/// @param name the catalog name. +/// @param flags the flags of the catalog. +/// @param kind the catalog kind. +/// @return catalog pointer. +/***********************************************************************************/ +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::CreateCatalog(_Input const Char* name, + _Input const Int32& flags, + _Input const Int32& kind) +{ + kout << "CreateCatalog(*...*)\r"; + + Lba out_lba = 0UL; + + kout << "Checking for path separator...\r"; + + /// a directory should have a slash in the end. + if (kind == kNeFSCatalogKindDir && + name[rt_string_len(name) - 1] != NeFileSystemHelper::Separator()) + return nullptr; + + /// a file shouldn't have a slash in the end. + if (kind != kNeFSCatalogKindDir && + name[rt_string_len(name) - 1] == NeFileSystemHelper::Separator()) + return nullptr; + + NEFS_CATALOG_STRUCT* catalog_copy = this->FindCatalog(name, out_lba); + + if (catalog_copy) + { + kout << "Catalog already exists: " << name << ".\r"; + err_global_get() = kErrorFileExists; + + delete catalog_copy; + catalog_copy = nullptr; + + return nullptr; + } + + Char parent_name[kNeFSCatalogNameLen] = {0}; + + for (SizeT indexName = 0UL; indexName < rt_string_len(name); ++indexName) + { + parent_name[indexName] = name[indexName]; + } + + if (*parent_name == 0) + { + kout << "Parent name is NUL.\r"; + err_global_get() = kErrorFileNotFound; + return nullptr; + } + + /// Locate parent catalog, to then allocate right after it. + + for (SizeT index_fill = 0; index_fill < rt_string_len(name); ++index_fill) + { + parent_name[index_fill] = name[index_fill]; + } + + SizeT index_reverse_copy = rt_string_len(parent_name); + + // zero character it. + parent_name[--index_reverse_copy] = 0; + + // mandatory / character, zero it. + parent_name[--index_reverse_copy] = 0; + + while (parent_name[index_reverse_copy] != NeFileSystemHelper::Separator()) + { + parent_name[index_reverse_copy] = 0; + --index_reverse_copy; + } + + NEFS_CATALOG_STRUCT* catalog = this->FindCatalog(parent_name, out_lba); + + auto& drive = kMountpoint.A(); + + constexpr auto kNeFSCatalogPadding = 4; + + if (catalog && catalog->Kind == kNeFSCatalogKindFile) + { + kout << "Parent is a file.\r"; + delete catalog; + + return nullptr; + } + else if (!catalog) + { + Char part_block[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + drive.fPacket.fPacketContent = part_block; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + NEFS_ROOT_PARTITION_BLOCK* blk_nefs = (NEFS_ROOT_PARTITION_BLOCK*)part_block; + out_lba = blk_nefs->StartCatalog; + } + + if (drive.fPacket.fPacketReadOnly) + return nullptr; + + NEFS_CATALOG_STRUCT* child_catalog = new NEFS_CATALOG_STRUCT(); + + child_catalog->Checksum = 0; + child_catalog->ResourceForkSize = 0UL; + child_catalog->DataForkSize = 0UL; + child_catalog->CatalogFlags = kNeFSStatusUnlocked; + child_catalog->NextSibling = out_lba; + child_catalog->PrevSibling = out_lba; + child_catalog->Kind = kind; + child_catalog->Flags |= kNeFSFlagCreated; + child_catalog->CatalogFlags = flags; + + SizeT i = rt_string_len(name); + + // get rid pf \0 + --i; + + if (kind == kNeFSCatalogKindDir) + --i; + + while (name[i] != '/') + --i; + + rt_copy_memory((VoidPtr)(name + i), (VoidPtr)child_catalog->Name, + rt_string_len(name)); + + NEFS_CATALOG_STRUCT temporary_catalog{}; + + Lba start_free = out_lba; + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + Char buf_part_block[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + drive.fPacket.fPacketContent = buf_part_block; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + NEFS_ROOT_PARTITION_BLOCK* part_block = (NEFS_ROOT_PARTITION_BLOCK*)buf_part_block; + + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fInput(drive.fPacket); + + if (part_block->FreeCatalog < 1) + { + delete child_catalog; + child_catalog = nullptr; + + return nullptr; + } + + kout << "Start finding catalog to allocate or empty space...\r"; + + while (start_free >= part_block->StartCatalog) + { + // ========================== // + // Allocate catalog now... + // ========================== // + if ((temporary_catalog.Flags & kNeFSFlagCreated) == 0) + { + child_catalog->NextSibling = + start_free + (sizeof(NEFS_CATALOG_STRUCT) * kNeFSCatalogPadding); + + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fOutput(drive.fPacket); + + child_catalog->DataFork = part_block->DiskSize - start_free; + child_catalog->ResourceFork = child_catalog->DataFork; + + drive.fPacket.fPacketContent = child_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fOutput(drive.fPacket); + + // Get NeFS partition's block. + + drive.fPacket.fPacketContent = buf_part_block; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + part_block->FreeSectors -= 1; + part_block->CatalogCount += 1; + part_block->FreeCatalog -= 1; + + drive.fOutput(drive.fPacket); + + kout << "Create new catalog with flags: " + << hex_number(child_catalog->Flags) << kendl; + kout << "Create new catalog with name: " << child_catalog->Name + << kendl; + + delete catalog; + catalog = nullptr; + + NEFS_CATALOG_STRUCT* found_catalog = new NEFS_CATALOG_STRUCT(); + rt_copy_memory(&temporary_catalog, found_catalog, sizeof(NEFS_CATALOG_STRUCT)); + + return found_catalog; + } + else if ((temporary_catalog.Flags & kNeFSFlagCreated) && + KStringBuilder::Equals(temporary_catalog.Name, name)) + { + rt_copy_memory(&temporary_catalog, child_catalog, sizeof(NEFS_CATALOG_STRUCT)); + + return child_catalog; + } + + start_free = start_free + (sizeof(NEFS_CATALOG_STRUCT) * kNeFSCatalogPadding); + + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + drive.fPacket.fPacketLba = start_free; + + drive.fInput(drive.fPacket); + } + + delete catalog; + return nullptr; +} + +/// @brief Make a EPM+NeFS drive out of the disk. +/// @param drive The drive to write on. +/// @return If it was sucessful, see err_global_get(). +bool NeFileSystemParser::Format(_Input _Output DriveTrait* drive, _Input const Lba endLba, _Input const Int32 flags, const Char* part_name) +{ + if (*part_name == 0 || + endLba == 0) + return false; + + // verify disk. + drive->fVerify(drive->fPacket); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive->fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + // if disk isn't good, then error out. + if (false == drive->fPacket.fPacketGood) + { + err_global_get() = kErrorDiskIsCorrupted; + return false; + } + + Char fs_buf[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + Lba start = kNeFSRootCatalogStartAddress; + + drive->fPacket.fPacketContent = fs_buf; + drive->fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive->fPacket.fPacketLba = start; + + drive->fInput(drive->fPacket); + + if (flags & kNeFSPartitionTypeBoot) + { + // make it bootable when needed. + Char buf_epm[kNeFSSectorSz] = {0}; + + EPM_PART_BLOCK* epm_boot = (EPM_PART_BLOCK*)buf_epm; + + // Write a new EPM entry. + + constexpr auto kFsName = "NeFS"; + constexpr auto kBlockName = "ZkaOS:"; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(kFsName)), epm_boot->Fs, rt_string_len(kFsName)); + + epm_boot->FsVersion = kNeFSVersionInteger; + epm_boot->LbaStart = start; + epm_boot->SectorSz = kNeFSSectorSz; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(kBlockName)), epm_boot->Name, rt_string_len(kBlockName)); + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(kEPMMagic)), epm_boot->Magic, rt_string_len(kEPMMagic)); + + Lba outEpmLba = kEPMBootBlockLba; + + Char buf[kNeFSSectorSz]; + + Lba prevStart = 0; + SizeT cnt = 0; + + while (drive->fPacket.fPacketGood) + { + drive->fPacket.fPacketContent = buf; + drive->fPacket.fPacketSize = sizeof(EPM_PART_BLOCK); + drive->fPacket.fPacketLba = outEpmLba; + + drive->fInput(drive->fPacket); + + if (buf[0] == 0) + { + epm_boot->LbaStart = prevStart; + + if (epm_boot->LbaStart) + epm_boot->LbaStart = outEpmLba; + + epm_boot->LbaEnd = endLba; + epm_boot->NumBlocks = cnt; + + drive->fPacket.fPacketContent = buf_epm; + drive->fPacket.fPacketSize = sizeof(EPM_PART_BLOCK); + drive->fPacket.fPacketLba = outEpmLba; + + drive->fOutput(drive->fPacket); + + break; + } + else + { + prevStart = ((EPM_PART_BLOCK*)buf)->LbaStart + ((EPM_PART_BLOCK*)buf)->LbaEnd; + } + + outEpmLba += sizeof(EPM_PART_BLOCK); + ++cnt; + } + } + + // disk isnt faulty and data has been fetched. + while (drive->fPacket.fPacketGood) + { + NEFS_ROOT_PARTITION_BLOCK* part_block = (NEFS_ROOT_PARTITION_BLOCK*)fs_buf; + + // check for an empty partition here. + if (part_block->PartitionName[0] == 0 && + rt_string_cmp(part_block->Ident, kNeFSIdent, kNeFSIdentLen)) + { + // partition is free and valid. + + part_block->Version = kNeFSVersionInteger; + + const auto kNeFSUntitledHD = part_name; + + rt_copy_memory((VoidPtr)kNeFSIdent, (VoidPtr)part_block->Ident, + kNeFSIdentLen); + + rt_copy_memory((VoidPtr)kNeFSUntitledHD, (VoidPtr)part_block->PartitionName, + rt_string_len(kNeFSUntitledHD)); + + SizeT catalogCount = 0UL; + + SizeT sectorCount = drv_get_sector_count(); + SizeT diskSize = drv_get_size(); + + part_block->Kind = kNeFSPartitionTypeStandard; + part_block->StartCatalog = kNeFSCatalogStartAddress; + part_block->Flags = kNeFSPartitionTypeStandard; + part_block->CatalogCount = sectorCount / sizeof(NEFS_CATALOG_STRUCT); + part_block->FreeSectors = sectorCount / sizeof(NEFS_CATALOG_STRUCT); + part_block->SectorCount = sectorCount; + part_block->DiskSize = diskSize; + part_block->FreeCatalog = sectorCount / sizeof(NEFS_CATALOG_STRUCT); + + drive->fPacket.fPacketContent = fs_buf; + drive->fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive->fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive->fOutput(drive->fPacket); + + kout << "drive kind: " << drive->fDriveKind() << kendl; + + kout << "partition name: " << part_block->PartitionName << kendl; + kout << "start: " << hex_number(part_block->StartCatalog) << kendl; + kout << "number of catalogs: " << hex_number(part_block->CatalogCount) << kendl; + kout << "free catalog: " << hex_number(part_block->FreeCatalog) << kendl; + kout << "free sectors: " << hex_number(part_block->FreeSectors) << kendl; + kout << "sector size: " << hex_number(part_block->SectorSize) << kendl; + + // write the root catalog. + this->CreateCatalog(kNeFSRoot, 0, kNeFSCatalogKindDir); + + return true; + } + + kout << "partition block already exists.\r"; + + start += part_block->DiskSize; + + drive->fPacket.fPacketContent = fs_buf; + drive->fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive->fPacket.fPacketLba = start; + + drive->fInput(drive->fPacket); + } + + return false; +} + +/// @brief Writes the data fork into a specific catalog. +/// @param catalog the catalog itself +/// @param data the data. +/// @return if the catalog w rote the contents successfully. +bool NeFileSystemParser::WriteCatalog(_Input const Char* catalog_name, Bool is_rsrc_fork, _Input VoidPtr data, _Input SizeT size_of_data, _Input const Char* fork_name) +{ + if (size_of_data < 1) + return No; + + auto buf = new UInt8[size_of_data]; + rt_set_memory(buf, 0, size_of_data); + + rt_copy_memory(data, buf, size_of_data); + + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + auto catalog = this->GetCatalog(catalog_name); + + if (!catalog) + { + delete[] buf; + buf = nullptr; + return NO; + } + + auto startFork = (!is_rsrc_fork) ? catalog->DataFork + : catalog->ResourceFork; + + delete catalog; + catalog = nullptr; + + NEFS_FORK_STRUCT* fork_data_input = new NEFS_FORK_STRUCT(); + NEFS_FORK_STRUCT prev_fork{}; + + kout << hex_number(startFork) << kendl; + + // sanity check of the fork position as the condition to run the loop. + while (startFork >= kNeFSCatalogStartAddress) + { + drive.fPacket.fPacketContent = fork_data_input; + drive.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drive.fPacket.fPacketLba = startFork; + + drive.fInput(drive.fPacket); + + kout << hex_number(fork_data_input->DataSize) << kendl; + kout << hex_number(size_of_data) << kendl; + kout << hex_number(fork_data_input->Flags) << kendl; + kout << fork_name << kendl; + kout << fork_data_input->ForkName << kendl; + kout << fork_data_input->CatalogName << kendl; + kout << catalog_name << kendl; + + if ((fork_data_input->Flags & kNeFSFlagCreated) && + KStringBuilder::Equals(fork_data_input->ForkName, fork_name) && + KStringBuilder::Equals(fork_data_input->CatalogName, catalog_name) && + fork_data_input->DataSize == size_of_data) + { + // ===================================================== // + // Store the blob now. + // ===================================================== // + + drive.fPacket.fPacketContent = buf; + drive.fPacket.fPacketSize = size_of_data; + drive.fPacket.fPacketLba = fork_data_input->DataOffset; + + kout << "data offset: " << hex_number(fork_data_input->DataOffset) << kendl; + + drive.fOutput(drive.fPacket); + + kout << "wrote data at offset: " << hex_number(fork_data_input->DataOffset) << kendl; + + delete fork_data_input; + delete[] buf; + + return true; + } + + // stumble upon a fork, store it. + + prev_fork = *fork_data_input; + + startFork = fork_data_input->NextSibling; + } + + delete[] buf; + delete fork_data_input; + + return false; +} + +/// @brief +/// @param catalog_name the catalog name. +/// @return the newly found catalog. +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::FindCatalog(_Input const Char* catalog_name, + Lba& out_lba, + Bool search_hidden, + Bool local_search) +{ + if (!catalog_name || + *catalog_name == 0) + return nullptr; + + NEFS_ROOT_PARTITION_BLOCK part{0}; + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + drive.fPacket.fPacketContent = ∂ + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + + drive.fInput(drive.fPacket); + + auto start_catalog_lba = kNeFSCatalogStartAddress; + const auto kStartCatalogList = start_catalog_lba; + + if (!KStringBuilder::Equals(catalog_name, NeFileSystemHelper::Root()) && local_search) + { + Char parent_name[kNeFSCatalogNameLen] = {0}; + + for (SizeT indexFill = 0; indexFill < rt_string_len(catalog_name); ++indexFill) + { + parent_name[indexFill] = catalog_name[indexFill]; + } + + SizeT indexReverseCopy = rt_string_len(parent_name); + + // zero character. + parent_name[--indexReverseCopy] = 0; + + // mandatory '/' character. + parent_name[--indexReverseCopy] = 0; + + while (parent_name[indexReverseCopy] != NeFileSystemHelper::Separator()) + { + parent_name[indexReverseCopy] = 0; + --indexReverseCopy; + } + + NEFS_CATALOG_STRUCT* parent_catalog = this->FindCatalog(parent_name, out_lba); + + if (parent_catalog && + !KStringBuilder::Equals(parent_name, NeFileSystemHelper::Root())) + { + start_catalog_lba = parent_catalog->NextSibling; + + delete parent_catalog; + parent_catalog = nullptr; + + local_search = YES; + } + else if (parent_catalog) + { + start_catalog_lba = parent_catalog->NextSibling; + + local_search = YES; + + delete parent_catalog; + parent_catalog = nullptr; + } + else if (!parent_catalog) + { + return nullptr; + } + } + + NEFS_CATALOG_STRUCT temporary_catalog{}; + + SizeT i = rt_string_len(catalog_name); + + // get rid of \0 + --i; + + if (catalog_name[i] == '/') + --i; + + while (catalog_name[i] != '/') + --i; + + const Char* tmp_name = (catalog_name + i); + +kNeFSSearchThroughCatalogList: + while (drive.fPacket.fPacketGood) + { + drive.fPacket.fPacketLba = start_catalog_lba; + drive.fPacket.fPacketContent = &temporary_catalog; + drive.fPacket.fPacketSize = sizeof(NEFS_CATALOG_STRUCT); + + drive.fInput(drive.fPacket); + + if (KStringBuilder::Equals(tmp_name, temporary_catalog.Name)) + { + if (temporary_catalog.Status == kNeFSStatusLocked && + !search_hidden) + { + err_global_get() = kErrorFileLocked; + + goto NeFSContinueSearch; + } + + /// ignore unallocated catalog, break + if (!(temporary_catalog.Flags & kNeFSFlagCreated)) + { + err_global_get() = kErrorFileNotFound; + + goto NeFSContinueSearch; + } + + kout << "Found available catalog at: " << hex_number(start_catalog_lba) << kendl; + kout << "Found available catalog at: " << temporary_catalog.Name << kendl; + + NEFS_CATALOG_STRUCT* catalog_ptr = new NEFS_CATALOG_STRUCT(); + rt_copy_memory(&temporary_catalog, catalog_ptr, sizeof(NEFS_CATALOG_STRUCT)); + + out_lba = start_catalog_lba; + return catalog_ptr; + } + + NeFSContinueSearch: + start_catalog_lba = temporary_catalog.NextSibling; + + if (start_catalog_lba < part.StartCatalog) + break; + } + + if (local_search) + { + local_search = false; + start_catalog_lba = part.StartCatalog; + + goto kNeFSSearchThroughCatalogList; + } + + err_global_get() = kErrorFileNotFound; + + out_lba = 0UL; + + return nullptr; +} + +/// @brief Get catalog from filesystem. +/// @param name the catalog's name/ +/// @return +_Output NEFS_CATALOG_STRUCT* NeFileSystemParser::GetCatalog(_Input const Char* name) +{ + Lba unused = 0; + return this->FindCatalog(name, unused, YES); +} + +/// @brief Closes a catalog, (frees it). +/// @param catalog the catalog to close. +/// @return +_Output Boolean NeFileSystemParser::CloseCatalog(_Input _Output NEFS_CATALOG_STRUCT* catalog) +{ + if (!catalog) + return false; + + delete catalog; + catalog = nullptr; + + return true; +} + +/// @brief Mark catalog as removed. +/// @param catalog The catalog structure. +/// @return if the catalog was removed or not. +_Output Boolean NeFileSystemParser::RemoveCatalog(_Input const Char* catalog_name) +{ + if (!catalog_name || + KStringBuilder::Equals(catalog_name, NeFileSystemHelper::Root())) + { + err_global_get() = kErrorInternal; + return false; + } + + Lba out_lba = 0; + auto catalog = this->FindCatalog(catalog_name, out_lba); + + if (out_lba >= kNeFSCatalogStartAddress || + catalog->Flags & kNeFSFlagCreated) + { + catalog->Flags &= (~kNeFSFlagCreated); + catalog->Flags |= kNeFSFlagDeleted; + + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + drive.fPacket.fPacketLba = out_lba; // the catalog position. + drive.fPacket.fPacketSize = + sizeof(NEFS_CATALOG_STRUCT); // size of catalog. roughly the sector size. + drive.fPacket.fPacketContent = catalog; // the catalog itself. + + drive.fOutput(drive.fPacket); // send packet. + + Char partitionBlockBuf[sizeof(NEFS_ROOT_PARTITION_BLOCK)] = {0}; + + drive.fPacket.fPacketLba = kNeFSRootCatalogStartAddress; + drive.fPacket.fPacketContent = partitionBlockBuf; + drive.fPacket.fPacketSize = sizeof(NEFS_ROOT_PARTITION_BLOCK); + + drive.fInput(drive.fPacket); + + NEFS_ROOT_PARTITION_BLOCK* part_block = + reinterpret_cast<NEFS_ROOT_PARTITION_BLOCK*>(partitionBlockBuf); + + --part_block->CatalogCount; + ++part_block->FreeSectors; + + drive.fOutput(drive.fPacket); + + return true; + } + + delete catalog; + catalog = nullptr; + + return false; +} + +/// ***************************************************************** /// +/// Reading,Seek,Tell are unimplemented on catalogs, refer to forks I/O instead. +/// ***************************************************************** /// + +/***********************************************************************************/ +/// @brief Read the catalog data fork. +/// @param catalog +/// @param dataSz +/// @return +/***********************************************************************************/ + +VoidPtr NeFileSystemParser::ReadCatalog(_Input _Output NEFS_CATALOG_STRUCT* catalog, + _Input Bool is_rsrc_fork, + _Input SizeT dataSz, + _Input const Char* forkName) +{ + if (!catalog) + { + err_global_get() = kErrorInvalidData; + return nullptr; + } + + Lba dataForkLba = (!is_rsrc_fork) ? catalog->DataFork : catalog->ResourceFork; + Size dataForkSize = (!is_rsrc_fork) ? catalog->DataForkSize : catalog->ResourceForkSize; + + kout << "catalog " << catalog->Name + << ", fork: " << hex_number(dataForkLba) << kendl; + + NEFS_FORK_STRUCT* fs_buf = new NEFS_FORK_STRUCT(); + auto& drive = kMountpoint.A(); + + rt_copy_memory((VoidPtr) "fs/nefs-packet", drive.fPacket.fPacketMime, + rt_string_len("fs/nefs-packet")); + + NEFS_FORK_STRUCT* fs_fork_data = nullptr; + + while (dataForkLba > kNeFSCatalogStartAddress) + { + drive.fPacket.fPacketLba = dataForkLba; + drive.fPacket.fPacketSize = sizeof(NEFS_FORK_STRUCT); + drive.fPacket.fPacketContent = fs_buf; + + drive.fInput(drive.fPacket); + + fs_fork_data = fs_buf; + + kout << "ForkName: " << fs_fork_data->ForkName << kendl; + kout << "CatalogName: " << fs_fork_data->CatalogName << kendl; + + if (KStringBuilder::Equals(forkName, fs_fork_data->ForkName) && + KStringBuilder::Equals(catalog->Name, fs_fork_data->CatalogName)) + break; + + dataForkLba = fs_fork_data->NextSibling; + } + + if (dataForkLba < kNeFSCatalogStartAddress) + { + delete fs_buf; + return nullptr; + } + + return fs_fork_data; +} + +/***********************************************************************************/ +/// @brief Seek in the data fork. +/// @param catalog the catalog offset. +/// @param off where to seek. +/// @return if the seeking was successful. +/***********************************************************************************/ + +bool NeFileSystemParser::Seek(_Input _Output NEFS_CATALOG_STRUCT* catalog, SizeT off) +{ + err_global_get() = kErrorUnimplemented; + return false; +} + +/***********************************************************************************/ +/// @brief Tell where we are inside the data fork. +/// @param catalog +/// @return The position on the file. +/***********************************************************************************/ + +SizeT NeFileSystemParser::Tell(_Input _Output NEFS_CATALOG_STRUCT* catalog) +{ + err_global_get() = kErrorUnimplemented; + return 0; +} + +namespace NeOS::NeFS +{ + /***********************************************************************************/ + /// @brief Construct NeFS drives. + /***********************************************************************************/ + Boolean fs_init_nefs(Void) noexcept + { + kout << "Creating main disk...\r"; + + kMountpoint.A() = io_construct_main_drive(); + + if (kMountpoint.A().fPacket.fPacketReadOnly == YES) + ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main filesystem cannot be mounted."); + + return YES; + } +} // namespace NeOS::NeFS + +#endif // ifdef __FSKIT_INCLUDES_NEFS__ diff --git a/dev/kernel/src/FileMgr.cc b/dev/kernel/src/FileMgr.cc new file mode 100644 index 00000000..b803253d --- /dev/null +++ b/dev/kernel/src/FileMgr.cc @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/FileMgr.h> +#include <NewKit/Utils.h> + +/// @file FileMgr.cc +//! @brief File System Manager API. + +namespace NeOS +{ + STATIC IFilesystemMgr* kMountedFilesystem = nullptr; + + /// @brief FilesystemMgr getter. + /// @return The mounted filesystem. + _Output IFilesystemMgr* IFilesystemMgr::GetMounted() + { + return kMountedFilesystem; + } + + /// @brief Unmount filesystem. + /// @return The unmounted filesystem. + _Output IFilesystemMgr* IFilesystemMgr::Unmount() + { + if (kMountedFilesystem) + { + auto mount = kMountedFilesystem; + kMountedFilesystem = nullptr; + + return mount; + } + + return nullptr; + } + + /// @brief Mount filesystem. + /// @param mount_ptr The filesystem to mount. + /// @return if it succeeded true, otherwise false. + _Output Bool IFilesystemMgr::Mount(_Input IFilesystemMgr* mount_ptr) + { + if (mount_ptr != nullptr) + { + kMountedFilesystem = mount_ptr; + return Yes; + } + + return No; + } +} // namespace NeOS diff --git a/dev/kernel/src/GUIDWizard.cc b/dev/kernel/src/GUIDWizard.cc new file mode 100644 index 00000000..96e15d85 --- /dev/null +++ b/dev/kernel/src/GUIDWizard.cc @@ -0,0 +1,72 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: GUIDWizard.cc + Purpose: GUID helper code + + Revision History: + +------------------------------------------- */ + +#include <CFKit/GUIDWizard.h> +#include <NewKit/Ref.h> + +// begin of ascii 'readable' characters. (A, C, C, 1, 2) +#define kUUIDAsciiBegin 47 +// @brief Size of UUID. +#define kUUIDSize 37 + +namespace CFKit::XRN::Version1 +{ + auto cf_make_sequence(const ArrayList<UInt32>& uuidSeq) -> Ref<GUIDSequence*> + { + GUIDSequence* seq = new GUIDSequence(); + MUST_PASS(seq); + + Ref<GUIDSequence*> seq_ref{seq}; + + seq_ref.Leak()->fMs1 = uuidSeq[0]; + seq_ref.Leak()->fMs2 = uuidSeq[1]; + seq_ref.Leak()->fMs3 = uuidSeq[2]; + seq_ref.Leak()->fMs4[0] = uuidSeq[3]; + seq_ref.Leak()->fMs4[1] = uuidSeq[4]; + seq_ref.Leak()->fMs4[2] = uuidSeq[5]; + seq_ref.Leak()->fMs4[3] = uuidSeq[6]; + seq_ref.Leak()->fMs4[4] = uuidSeq[7]; + seq_ref.Leak()->fMs4[5] = uuidSeq[8]; + seq_ref.Leak()->fMs4[6] = uuidSeq[9]; + seq_ref.Leak()->fMs4[7] = uuidSeq[10]; + + return seq_ref; + } + + // @brief Tries to make a guid out of a string. + // This function is not complete for now + auto cf_try_guid_to_string(Ref<GUIDSequence*>& seq) -> ErrorOr<Ref<KString>> + { + Char buf[kUUIDSize]; + + for (SizeT index = 0; index < 16; ++index) + { + buf[index] = seq.Leak()->u8[index] + kUUIDAsciiBegin; + } + + for (SizeT index = 16; index < 24; ++index) + { + buf[index] = seq.Leak()->u16[index] + kUUIDAsciiBegin; + } + + for (SizeT index = 24; index < 28; ++index) + { + buf[index] = seq.Leak()->u32[index] + kUUIDAsciiBegin; + } + + auto view = KStringBuilder::Construct(buf); + + if (view) + return ErrorOr<Ref<KString>>{view.Leak()}; + + return ErrorOr<Ref<KString>>{-1}; + } +} // namespace CFKit::XRN::Version1 diff --git a/dev/kernel/src/GUIDWrapper.cc b/dev/kernel/src/GUIDWrapper.cc new file mode 100644 index 00000000..cd4a6aa3 --- /dev/null +++ b/dev/kernel/src/GUIDWrapper.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <CFKit/GUIDWrapper.h> + +namespace CFKit::XRN +{ +} diff --git a/dev/kernel/src/HardwareThreadScheduler.cc b/dev/kernel/src/HardwareThreadScheduler.cc new file mode 100644 index 00000000..70502d40 --- /dev/null +++ b/dev/kernel/src/HardwareThreadScheduler.cc @@ -0,0 +1,225 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/HardwareThreadScheduler.h> +#include <CFKit/Property.h> + +/***********************************************************************************/ +///! @file HardwareThreadScheduler.cc +///! @brief This file handles multi processing in the Kernel. +///! @brief Multi processing is needed for multi-tasking operations. +/***********************************************************************************/ + +namespace NeOS +{ + /***********************************************************************************/ + /// @note Those symbols are needed in order to switch and validate the stack. + /***********************************************************************************/ + + EXTERN_C Bool hal_check_stack(HAL::StackFramePtr frame); + EXTERN_C Bool mp_register_process(HAL::StackFramePtr frame, ProcessID pid); + + STATIC HardwareThreadScheduler kHardwareThreadScheduler; + + ///! A HardwareThread class takes care of it's owned hardware thread. + ///! It has a stack for it's core. + + /***********************************************************************************/ + ///! @brief C++ constructor. + /***********************************************************************************/ + HardwareThread::HardwareThread() = default; + + /***********************************************************************************/ + ///! @brief C++ destructor. + /***********************************************************************************/ + HardwareThread::~HardwareThread() = default; + + /***********************************************************************************/ + //! @brief returns the id of the thread. + /***********************************************************************************/ + const ThreadID& HardwareThread::ID() noexcept + { + return fID; + } + + /***********************************************************************************/ + //! @brief returns the kind of thread we have. + /***********************************************************************************/ + const ThreadKind& HardwareThread::Kind() noexcept + { + return fKind; + } + + /***********************************************************************************/ + //! @brief is the thread busy? + //! @return whether the thread is busy or not. + /***********************************************************************************/ + Bool HardwareThread::IsBusy() noexcept + { + STATIC Int64 busy_timer = 0U; + constexpr Int64 kTimeoutMax = 0x1000000; // an arbitrary value used to tell if the timeout hasn't been reached yet. + + if (fBusy && (busy_timer > kTimeoutMax)) + { + busy_timer = 0U; + fBusy = No; + + return No; + } + + ++busy_timer; + + return fBusy; + } + + /***********************************************************************************/ + /// @brief Get processor stack frame. + /***********************************************************************************/ + + HAL::StackFramePtr HardwareThread::StackFrame() noexcept + { + MUST_PASS(this->fStack); + return this->fStack; + } + + Void HardwareThread::Busy(const Bool busy) noexcept + { + this->fBusy = busy; + } + + HardwareThread::operator bool() + { + return this->fStack && !this->fBusy; + } + + /***********************************************************************************/ + /// @brief Wakeup the processor. + /***********************************************************************************/ + + Void HardwareThread::Wake(const bool wakeup) noexcept + { + this->fWakeup = wakeup; + } + + /***********************************************************************************/ + /// @brief Switch to hardware thread. + /// @param stack the new hardware thread. + /// @retval true stack was changed, code is running. + /// @retval false stack is invalid, previous code is running. + /***********************************************************************************/ + Bool HardwareThread::Switch(VoidPtr image_ptr, Ptr8 stack_ptr, HAL::StackFramePtr frame, const ThreadID& pid) + { + if (this->IsBusy()) + return NO; + + this->fStack = frame; + this->fPID = pid; + + this->fStack->BP = reinterpret_cast<UIntPtr>(image_ptr); + this->fStack->SP = reinterpret_cast<UIntPtr>(stack_ptr); + + Bool ret = mp_register_process(fStack, this->fPID); + + if (ret) + this->Busy(YES); + + return ret; + } + + /***********************************************************************************/ + ///! @brief Tells if processor is waked up. + /***********************************************************************************/ + bool HardwareThread::IsWakeup() noexcept + { + return this->fWakeup; + } + + /***********************************************************************************/ + ///! @brief Constructor and destructors. + ///! @brief Default constructor. + /***********************************************************************************/ + + HardwareThreadScheduler::HardwareThreadScheduler() = default; + + /***********************************************************************************/ + ///! @brief Default destructor. + /***********************************************************************************/ + HardwareThreadScheduler::~HardwareThreadScheduler() = default; + + /***********************************************************************************/ + /// @brief Shared singleton function + /***********************************************************************************/ + HardwareThreadScheduler& HardwareThreadScheduler::The() + { + return kHardwareThreadScheduler; + } + + /***********************************************************************************/ + /// @brief Get Stack Frame of AP. + /***********************************************************************************/ + HAL::StackFramePtr HardwareThreadScheduler::Leak() noexcept + { + return fThreadList[fCurrentThread].fStack; + } + + /***********************************************************************************/ + /** + * Get Hardware thread at index. + * @param idx the index + * @return the reference to the hardware thread. + */ + /***********************************************************************************/ + Ref<HardwareThread*> HardwareThreadScheduler::operator[](const SizeT& idx) + { + if (idx == 0) + { + if (fThreadList[idx].Kind() != kAPSystemReserved) + { + fThreadList[idx].fKind = kAPBoot; + } + } + else if (idx >= kMaxAPInsideSched) + { + static HardwareThread* kFakeThread = nullptr; + return {kFakeThread}; + } + + return &fThreadList[idx]; + } + + /***********************************************************************************/ + /** + * Check if thread pool isn't empty. + * @return + */ + /***********************************************************************************/ + HardwareThreadScheduler::operator bool() noexcept + { + return !fThreadList.Empty(); + } + + /***********************************************************************************/ + /** + * Reverse operator bool + * @return + */ + /***********************************************************************************/ + bool HardwareThreadScheduler::operator!() noexcept + { + return fThreadList.Empty(); + } + + /***********************************************************************************/ + /// @brief Returns the amount of core present. + /// @return the number of APs. + /***********************************************************************************/ + SizeT HardwareThreadScheduler::Capacity() noexcept + { + return fThreadList.Count(); + } +} // namespace NeOS diff --git a/dev/kernel/src/IDylibObject.cc b/dev/kernel/src/IDylibObject.cc new file mode 100644 index 00000000..30a76af9 --- /dev/null +++ b/dev/kernel/src/IDylibObject.cc @@ -0,0 +1,15 @@ +/* + * ======================================================== + * + * neoskrnl + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#include <KernelKit/IDylibObject.h> +#include <KernelKit/DebugOutput.h> + +#include <KernelKit/UserProcessScheduler.h> + +using namespace NeOS; diff --git a/dev/kernel/src/IPEFDylibObject.cc b/dev/kernel/src/IPEFDylibObject.cc new file mode 100644 index 00000000..e994ad29 --- /dev/null +++ b/dev/kernel/src/IPEFDylibObject.cc @@ -0,0 +1,111 @@ +/* + * ======================================================== + * + * neoskrnl + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/PEF.h> +#include <KernelKit/IPEFDylibObject.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/ThreadLocalStorage.h> +#include <NewKit/Defines.h> + +/* ------------------------------------------- + + Revision History: + + 01/02/24: Reworked dll ABI, expect a rtl_init_dylib and + rtl_fini_dylib (amlel) + + 15/02/24: Breaking changes, changed the name of the + routines. (amlel) + + 07/28/24: Replace rt_library_free with rtl_fini_dylib + + 10/8/24: FIX: Fix log comment. + + ------------------------------------------- */ + +using namespace NeOS; + +/***********************************************************************************/ +/// @file IPEFDylibObject.cc +/// @brief PEF's Dylib runtime. +/***********************************************************************************/ + +/***********************************************************************************/ +/** @brief Library initializer. */ +/***********************************************************************************/ + +EXTERN_C IDylibRef rtl_init_dylib(UserProcess& process) +{ + IDylibRef dll_obj = tls_new_class<IPEFDylibObject>(); + + if (!dll_obj) + { + process.Crash(); + return nullptr; + } + + dll_obj->Mount(new IPEFDylibObject::DLL_TRAITS()); + + if (!dll_obj->Get()) + { + tls_delete_class(dll_obj); + dll_obj = nullptr; + + process.Crash(); + + return nullptr; + } + + dll_obj->Get()->ImageObject = + process.Image.fBlob; + + if (!dll_obj->Get()->ImageObject) + { + delete dll_obj->Get(); + + tls_delete_class(dll_obj); + dll_obj = nullptr; + + process.Crash(); + + return nullptr; + } + + dll_obj->Get()->ImageEntrypointOffset = + dll_obj->Load<VoidPtr>(kPefStart, rt_string_len(kPefStart, 0), kPefCode); + + return dll_obj; +} + +/***********************************************************************************/ +/** @brief Frees the dll_obj. */ +/** @note Please check if the dll_obj got freed! */ +/** @param dll_obj The dll_obj to free. */ +/** @param successful Reports if successful or not. */ +/***********************************************************************************/ + +EXTERN_C Void rtl_fini_dylib(UserProcess& process, IDylibRef dll_obj, BOOL* successful) +{ + MUST_PASS(successful); + + // sanity check (will also trigger a bug check if this fails) + if (dll_obj == nullptr) + { + *successful = false; + process.Crash(); + } + + delete dll_obj->Get(); + delete dll_obj; + + dll_obj = nullptr; + + *successful = true; +} diff --git a/dev/kernel/src/IndexableProperty.cc b/dev/kernel/src/IndexableProperty.cc new file mode 100644 index 00000000..404cddc3 --- /dev/null +++ b/dev/kernel/src/IndexableProperty.cc @@ -0,0 +1,57 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <CompilerKit/CompilerKit.h> +#include <FSKit/IndexableProperty.h> +#include <NewKit/MutableArray.h> +#include <NewKit/Utils.h> + +/// @brief File indexer API for fast path access. +/// BUGS: 0 + +#define kMaxLenIndexer (256U) + +namespace NeOS +{ + namespace Indexer + { + IndexProperty& IndexableProperty::Leak() noexcept + { + return fIndex; + } + + Void IndexableProperty::AddFlag(Int16 flag) + { + fFlags |= flag; + } + + Void IndexableProperty::RemoveFlag(Int16 flag) + { + fFlags &= flag; + } + + Int16 IndexableProperty::HasFlag(Int16 flag) + { + return fFlags & flag; + } + + /// @brief Index a file into the indexer instance. + /// @param filename filesystem path to access. + /// @param filenameLen used bytes in path. + /// @param indexer the filesystem indexer. + /// @return none, check before if indexer can be claimed (using indexer.HasFlag(kIndexerClaimed)). + Void fs_index_file(const Char* filename, SizeT filenameLen, IndexableProperty& indexer) + { + if (!indexer.HasFlag(kIndexerClaimed)) + { + indexer.AddFlag(kIndexerClaimed); + rt_copy_memory((VoidPtr)indexer.Leak().Path, (VoidPtr)filename, filenameLen); + + kout << "FSKit: Indexed new file: " << filename << kendl; + } + } + } // namespace Indexer +} // namespace NeOS diff --git a/dev/kernel/src/Json.cc b/dev/kernel/src/Json.cc new file mode 100644 index 00000000..48567b5f --- /dev/null +++ b/dev/kernel/src/Json.cc @@ -0,0 +1,10 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Json.h> + +/// @brief Undefined object, is null in length. +RTL_INIT_OBJECT(NeOS::Json::kNull, NeOS::Json); diff --git a/dev/kernel/src/KString.cc b/dev/kernel/src/KString.cc new file mode 100644 index 00000000..d96ef38c --- /dev/null +++ b/dev/kernel/src/KString.cc @@ -0,0 +1,218 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/KString.h> +#include <NewKit/Utils.h> + +/// @file KString.cc +/// @brief Kernel String manipulation file. + +namespace NeOS +{ + Char* KString::Data() + { + return this->fData; + } + + const Char* KString::CData() const + { + return const_cast<const Char*>(this->fData); + } + + Size KString::Length() const + { + return this->fDataSz; + } + + bool KString::operator==(const KString& rhs) const + { + if (rhs.Length() != this->Length()) + return false; + + for (Size index = 0; index < this->Length(); ++index) + { + if (rhs.fData[index] != this->fData[index]) + return false; + } + + return true; + } + + bool KString::operator==(const Char* rhs) const + { + if (rt_string_len(rhs) != this->Length()) + return false; + + for (Size index = 0; index < rt_string_len(rhs); ++index) + { + if (rhs[index] != this->fData[index]) + return false; + } + + return true; + } + + bool KString::operator!=(const KString& rhs) const + { + if (rhs.Length() != this->Length()) + return false; + + for (Size index = 0; index < rhs.Length(); ++index) + { + if (rhs.fData[index] == this->fData[index]) + return false; + } + + return true; + } + + bool KString::operator!=(const Char* rhs) const + { + if (rt_string_len(rhs) != this->Length()) + return false; + + for (Size index = 0; index < rt_string_len(rhs); ++index) + { + if (rhs[index] == this->fData[index]) + return false; + } + + return true; + } + + ErrorOr<KString> KStringBuilder::Construct(const Char* data) + { + if (!data || *data == 0) + return {}; + + KString* view = new KString(rt_string_len(data)); + (*view) += data; + + return ErrorOr<KString>(*view); + } + + const Char* KStringBuilder::FromBool(const Char* fmt, bool i) + { + if (!fmt) + return ("?"); + + const Char* boolean_expr = i ? "YES" : "NO"; + Char* ret = (Char*)RTL_ALLOCA((sizeof(char) * i) ? 4 : 5 + rt_string_len(fmt)); + + if (!ret) + return ("?"); + + const auto fmt_len = rt_string_len(fmt); + const auto res_len = rt_string_len(boolean_expr); + + for (Size idx = 0; idx < fmt_len; ++idx) + { + if (fmt[idx] == '%') + { + SizeT result_cnt = idx; + + for (auto y_idx = idx; y_idx < res_len; ++y_idx) + { + ret[result_cnt] = boolean_expr[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; + } + + bool KStringBuilder::Equals(const Char* lhs, const Char* rhs) + { + if (rt_string_len(rhs) != rt_string_len(lhs)) + return false; + + for (Size index = 0; index < rt_string_len(rhs); ++index) + { + if (rhs[index] != lhs[index]) + return false; + } + + return true; + } + + bool KStringBuilder::Equals(const WideChar* lhs, const WideChar* rhs) + { + for (Size index = 0; rhs[index] != 0; ++index) + { + if (rhs[index] != lhs[index]) + return false; + } + + return true; + } + + const Char* KStringBuilder::Format(const Char* fmt, const Char* fmt2) + { + if (!fmt || !fmt2) + return ("?"); + + Char* ret = + (Char*)RTL_ALLOCA(sizeof(char) * (rt_string_len(fmt2) + rt_string_len(fmt))); + + if (!ret) + return ("?"); + + const auto len = rt_string_len(fmt); + + for (Size idx = 0; idx < len; ++idx) + { + if (fmt[idx] == '%' && idx < rt_string_len(fmt) && fmt[idx] == 's') + { + Size result_cnt = idx; + + for (Size y_idx = 0; y_idx < rt_string_len(fmt2); ++y_idx) + { + ret[result_cnt] = fmt2[y_idx]; + ++result_cnt; + } + } + + ret[idx] = fmt[idx]; + } + + return ret; + } + + STATIC void rt_string_append(Char* lhs, const Char* rhs, Int32 cur) + { + SizeT sz_rhs = rt_string_len(rhs); + SizeT rhs_i = 0; + + for (; rhs_i < sz_rhs; ++rhs_i) + { + lhs[rhs_i + cur] = rhs[rhs_i]; + } + } + + KString& KString::operator+=(const Char* rhs) + { + rt_string_append(this->fData, rhs, this->fCur); + this->fCur += rt_string_len(rhs); + + return *this; + } + + KString& KString::operator+=(const KString& rhs) + { + if (rt_string_len(rhs.fData) > this->Length()) + return *this; + + rt_string_append(this->fData, const_cast<Char*>(rhs.fData), this->fCur); + this->fCur += rt_string_len(const_cast<Char*>(rhs.fData)); + + return *this; + } +} // namespace NeOS diff --git a/dev/kernel/src/LPC.cc b/dev/kernel/src/LPC.cc new file mode 100644 index 00000000..b6b2e11b --- /dev/null +++ b/dev/kernel/src/LPC.cc @@ -0,0 +1,34 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/LPC.h> +#include <NewKit/KernelPanic.h> + +namespace NeOS +{ + STATIC Bool kRaiseOnBugCheck = false; + + /// @brief Does a system wide bug check. + /// @param void no params. + /// @return if error-free: false, otherwise true. + Boolean err_bug_check(void) noexcept + { + if (kRaiseOnBugCheck) + { + ke_panic(RUNTIME_CHECK_BAD_BEHAVIOR); + } + + return No; + } + + /// @brief Tells if we should raise a bug check not. + /// @param void + /// @return void + Void err_bug_check_raise(Void) noexcept + { + kRaiseOnBugCheck = true; + } +} // namespace NeOS diff --git a/dev/kernel/src/LockDelegate.cc b/dev/kernel/src/LockDelegate.cc new file mode 100644 index 00000000..df62c6f3 --- /dev/null +++ b/dev/kernel/src/LockDelegate.cc @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/LockDelegate.h> + +namespace NeOS +{ + /// @note Leave it empty for now. +} // namespace NeOS diff --git a/dev/kernel/src/MemoryMgr.cc b/dev/kernel/src/MemoryMgr.cc new file mode 100644 index 00000000..4e13ea15 --- /dev/null +++ b/dev/kernel/src/MemoryMgr.cc @@ -0,0 +1,289 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/LPC.h> +#include <KernelKit/MemoryMgr.h> +#include <NewKit/Crc32.h> +#include <NewKit/PageMgr.h> +#include <NewKit/Utils.h> +#include <ArchKit/ArchKit.h> + +/* ------------------------------------------- + + Revision History: + 10/8/24: FIX: Fix useless long name, alongside a new WR (WriteRead) field. + 20/10/24: Fix mm_new_ and mm_delete_ APIs inside MemoryMgr.h header. (amlal) + 27/01/25: Reworked code as the memory manager. + + ------------------------------------------- */ + +//! @file MemoryMgr.cc +//! @brief Heap algorithm that serves as the main memory manager. + +#define kKernelHeapMagic (0xD4D75) +#define kKernelHeapAlignSz (__BIGGEST_ALIGNMENT__) + +namespace NeOS +{ + /// @brief Contains data structures and algorithms for the heap. + namespace Detail + { + struct PACKED HEAP_INFORMATION_BLOCK; + + /// @brief Kernel heap information block. + /// Located before the address bytes. + /// | HIB | CLASS/STRUCT/DATA TYPES... | + struct PACKED HEAP_INFORMATION_BLOCK final + { + ///! @brief 32-bit value which contains the magic number of the heap. + UInt32 fMagic : 24; + + ///! @brief Is the heap present? + UInt8 fPresent : 1; + + /// @brief Is this value writable? + UInt8 fWriteRead : 1; + + /// @brief Is this value owned by the user? + UInt8 fUser : 1; + + /// @brief Is this a page pointer? + UInt8 fPage : 1; + + /// @brief 32-bit CRC checksum. + UInt32 fCRC32; + + /// @brief 64-bit Allocation flags. + UInt16 fFlags; + + /// @brief 64-bit pointer size. + SizeT fSize; + + /// @brief 64-bit target offset pointer. + UIntPtr fOffset; + + /// @brief Padding bytes for header. + UInt8 fPadding[kKernelHeapAlignSz]; + }; + + /// @brief Check for heap address validity. + /// @param heap_ptr The address_ptr to check. + /// @return Bool if the pointer is valid or not. + _Output auto mm_check_heap_address(VoidPtr heap_ptr) -> Bool + { + if (!heap_ptr) + return false; + + auto base_heap = ((IntPtr)heap_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK); + + /// Add that check in case we're having an integer underflow. /// + + if (base_heap < 0) + { + return false; + } + + return true; + } + + typedef HEAP_INFORMATION_BLOCK* HEAP_INFORMATION_BLOCK_PTR; + } // namespace Detail + + /// @brief Declare a new size for ptr_heap. + /// @param ptr_heap the pointer. + /// @return Newly allocated heap header. + _Output auto mm_realloc_heap(VoidPtr ptr_heap, SizeT new_sz) -> VoidPtr + { + if (Detail::mm_check_heap_address(ptr_heap) == No) + return nullptr; + + if (!ptr_heap || new_sz < 1) + return nullptr; + + kout << "This function is not implemented by NeOSKrnl, please use the BSD's realloc instead.\r"; + ke_panic(RUNTIME_CHECK_INVALID); + + return nullptr; + } + + /// @brief Allocate chunk of memory. + /// @param sz Size of pointer + /// @param wr Read Write bit. + /// @param user User enable bit. + /// @return The newly allocated pointer. + _Output VoidPtr mm_new_heap(const SizeT sz, const bool wr, const bool user) + { + auto sz_fix = sz; + + if (sz_fix == 0) + return nullptr; + + sz_fix += sizeof(Detail::HEAP_INFORMATION_BLOCK); + + PageMgr heap_mgr; + auto wrapper = heap_mgr.Request(wr, user, No, sz_fix); + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + wrapper.VirtualAddress() + sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + heap_info_ptr->fSize = sz_fix; + heap_info_ptr->fMagic = kKernelHeapMagic; + heap_info_ptr->fCRC32 = 0; // dont fill it for now. + heap_info_ptr->fOffset = reinterpret_cast<UIntPtr>(heap_info_ptr) + sizeof(Detail::HEAP_INFORMATION_BLOCK); + heap_info_ptr->fPage = No; + heap_info_ptr->fWriteRead = wr; + heap_info_ptr->fUser = user; + heap_info_ptr->fPresent = Yes; + + rt_set_memory(heap_info_ptr->fPadding, 0, kKernelHeapAlignSz); + + auto result = reinterpret_cast<VoidPtr>(heap_info_ptr->fOffset); + + kout << "Registered heap address: " << hex_number(reinterpret_cast<UIntPtr>(heap_info_ptr)) << kendl; + + return result; + } + + /// @brief Makes a page heap. + /// @param heap_ptr the pointer to make a page heap. + /// @return kErrorSuccess if successful, otherwise an error code. + _Output Int32 mm_make_page(VoidPtr heap_ptr) + { + if (Detail::mm_check_heap_address(heap_ptr) == No) + return kErrorHeapNotPresent; + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (!heap_info_ptr) + return kErrorHeapNotPresent; + + heap_info_ptr->fPage = true; + + kout << "Registered page address: " << hex_number(reinterpret_cast<UIntPtr>(heap_info_ptr)) << kendl; + + return kErrorSuccess; + } + + /// @brief Overwrites and set the flags of a heap header. + /// @param heap_ptr the pointer to update. + /// @param flags the flags to set. + _Output Int32 mm_make_flags(VoidPtr heap_ptr, UInt64 flags) + { + if (Detail::mm_check_heap_address(heap_ptr) == No) + return kErrorHeapNotPresent; + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (!heap_info_ptr) + return kErrorHeapNotPresent; + + heap_info_ptr->fFlags = flags; + + return kErrorSuccess; + } + + /// @brief Gets the flags of a heap header. + /// @param heap_ptr the pointer to get. + _Output UInt64 mm_get_flags(VoidPtr heap_ptr) + { + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (!heap_info_ptr) + return kErrorHeapNotPresent; + + return heap_info_ptr->fFlags; + } + + /// @brief Declare pointer as free. + /// @param heap_ptr the pointer. + /// @return + _Output Int32 mm_delete_heap(VoidPtr heap_ptr) + { + if (Detail::mm_check_heap_address(heap_ptr) == No) + return kErrorHeapNotPresent; + + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)(heap_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + if (heap_info_ptr && heap_info_ptr->fMagic == kKernelHeapMagic) + { + if (!heap_info_ptr->fPresent) + { + return kErrorHeapNotPresent; + } + + heap_info_ptr->fSize = 0UL; + heap_info_ptr->fPresent = No; + heap_info_ptr->fOffset = 0; + heap_info_ptr->fCRC32 = 0; + heap_info_ptr->fWriteRead = No; + heap_info_ptr->fUser = No; + heap_info_ptr->fMagic = 0; + + PTEWrapper page_wrapper(No, No, No, reinterpret_cast<UIntPtr>(heap_info_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + Ref<PTEWrapper> pte_address{page_wrapper}; + + PageMgr heap_mgr; + heap_mgr.Free(pte_address); + + kout << "Address has been successfully freed." << kendl; + + return kErrorSuccess; + } + + return kErrorInternal; + } + + /// @brief Check if pointer is a valid Kernel pointer. + /// @param heap_ptr the pointer + /// @return if it exists. + _Output Boolean mm_is_valid_heap(VoidPtr heap_ptr) + { + if (heap_ptr && HAL::mm_is_bitmap(heap_ptr)) + { + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)(heap_ptr) - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + return (heap_info_ptr && heap_info_ptr->fPresent && heap_info_ptr->fMagic == kKernelHeapMagic); + } + + return No; + } + + /// @brief Protect the heap with a CRC value. + /// @param heap_ptr HIB pointer. + /// @return if it valid: point has crc now., otherwise fail. + _Output Boolean mm_protect_heap(VoidPtr heap_ptr) + { + if (heap_ptr) + { + Detail::HEAP_INFORMATION_BLOCK_PTR heap_info_ptr = + reinterpret_cast<Detail::HEAP_INFORMATION_BLOCK_PTR>( + (UIntPtr)heap_ptr - sizeof(Detail::HEAP_INFORMATION_BLOCK)); + + /// if valid, present and is heap header, then compute crc32 + if (heap_info_ptr && heap_info_ptr->fPresent && kKernelHeapMagic == heap_info_ptr->fMagic) + { + heap_info_ptr->fCRC32 = + ke_calculate_crc32((Char*)heap_info_ptr->fOffset, heap_info_ptr->fSize); + + return Yes; + } + } + + return No; + } +} // namespace NeOS diff --git a/dev/kernel/src/MutableArray.cc b/dev/kernel/src/MutableArray.cc new file mode 100644 index 00000000..8464a283 --- /dev/null +++ b/dev/kernel/src/MutableArray.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/MutableArray.h> diff --git a/dev/kernel/src/Network/IPAddr.cc b/dev/kernel/src/Network/IPAddr.cc new file mode 100644 index 00000000..6f523086 --- /dev/null +++ b/dev/kernel/src/Network/IPAddr.cc @@ -0,0 +1,129 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/IP.h> +#include <NewKit/Utils.h> + +namespace NeOS +{ + Char* RawIPAddress::Address() + { + return fAddr; + } + + RawIPAddress::RawIPAddress(char bytes[4]) + { + rt_copy_memory(bytes, fAddr, 4); + } + + BOOL RawIPAddress::operator==(const RawIPAddress& ipv4) + { + for (Size index = 0; index < 4; ++index) + { + if (ipv4.fAddr[index] != fAddr[index]) + return false; + } + + return true; + } + + BOOL RawIPAddress::operator!=(const RawIPAddress& ipv4) + { + for (Size index = 0; index < 4; ++index) + { + if (ipv4.fAddr[index] == fAddr[index]) + return false; + } + + return true; + } + + Char& RawIPAddress::operator[](const Size& index) + { + kout << "[RawIPAddress::operator[]] Fetching Index...\r"; + + static char IP_PLACEHOLDER = '0'; + if (index > 4) + return IP_PLACEHOLDER; + + return fAddr[index]; + } + + RawIPAddress6::RawIPAddress6(char bytes[8]) + { + rt_copy_memory(bytes, fAddr, 8); + } + + char& RawIPAddress6::operator[](const Size& index) + { + kout << "[RawIPAddress6::operator[]] Fetching Index...\r"; + + static char IP_PLACEHOLDER = '0'; + if (index > 8) + return IP_PLACEHOLDER; + + return fAddr[index]; + } + + bool RawIPAddress6::operator==(const RawIPAddress6& ipv6) + { + for (SizeT index = 0; index < 8; ++index) + { + if (ipv6.fAddr[index] != fAddr[index]) + return false; + } + + return true; + } + + bool RawIPAddress6::operator!=(const RawIPAddress6& ipv6) + { + for (SizeT index = 0; index < 8; ++index) + { + if (ipv6.fAddr[index] == fAddr[index]) + return false; + } + + return true; + } + + ErrorOr<KString> IPFactory::ToKString(Ref<RawIPAddress6>& ipv6) + { + auto str = KStringBuilder::Construct(ipv6.Leak().Address()); + return str; + } + + ErrorOr<KString> IPFactory::ToKString(Ref<RawIPAddress>& ipv4) + { + auto str = KStringBuilder::Construct(ipv4.Leak().Address()); + return str; + } + + bool IPFactory::IpCheckVersion4(const Char* ip) + { + if (!ip) + return NO; + + Int32 cnter = 0; + + for (SizeT base = 0; base < rt_string_len(ip); ++base) + { + if (ip[base] == '.') + { + cnter = 0; + } + else + { + if (cnter == 3) + return false; + + ++cnter; + } + } + + return true; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/IPCAddr.cc b/dev/kernel/src/Network/IPCAddr.cc new file mode 100644 index 00000000..75a54a36 --- /dev/null +++ b/dev/kernel/src/Network/IPCAddr.cc @@ -0,0 +1,32 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + ------------------------------------------- */ + +#include <NetworkKit/IPC.h> +#include <KernelKit/LPC.h> +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + bool IPC_ADDR::operator==(const IPC_ADDR& addr) noexcept + { + return addr.UserProcessID == this->UserProcessID && addr.UserProcessTeam == this->UserProcessTeam; + } + + bool IPC_ADDR::operator==(IPC_ADDR& addr) noexcept + { + return addr.UserProcessID == this->UserProcessID && addr.UserProcessTeam == this->UserProcessTeam; + } + + bool IPC_ADDR::operator!=(const IPC_ADDR& addr) noexcept + { + return addr.UserProcessID != this->UserProcessID || addr.UserProcessTeam != this->UserProcessTeam; + } + + bool IPC_ADDR::operator!=(IPC_ADDR& addr) noexcept + { + return addr.UserProcessID != this->UserProcessID || addr.UserProcessTeam != this->UserProcessTeam; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/IPCMsg.cc b/dev/kernel/src/Network/IPCMsg.cc new file mode 100644 index 00000000..f5bec6f7 --- /dev/null +++ b/dev/kernel/src/Network/IPCMsg.cc @@ -0,0 +1,125 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/IPC.h> +#include <KernelKit/LPC.h> +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + /// @internal internal use for IPC system only. + /// @brief The internal sanitize function. + Bool ipc_int_sanitize_packet(IPC_MSG* pckt) + { + auto endian = RTL_ENDIAN(pckt, ((Char*)pckt)[0]); + + switch (endian) + { + case Endian::kEndianBig: { + if (pckt->IpcEndianess == kIPCLittleEndian) + goto ipc_check_failed; + + break; + } + case Endian::kEndianLittle: { + if (pckt->IpcEndianess == kIPCBigEndian) + goto ipc_check_failed; + + break; + } + case Endian::kEndianMixed: { + if (pckt->IpcEndianess == kIPCMixedEndian) + goto ipc_check_failed; + + break; + } + default: + goto ipc_check_failed; + } + + if (pckt->IpcFrom == pckt->IpcTo || + pckt->IpcPacketSize > kIPCMsgSize) + { + goto ipc_check_failed; + } + + return pckt->IpcPacketSize > 1 && pckt->IpcHeaderMagic == kIPCHeaderMagic; + + ipc_check_failed: + err_local_get() = kErrorIPC; + return false; + } + + /// @brief Sanitize packet function + /// @retval true packet is correct. + /// @retval false packet is incorrect and process has crashed. + Bool ipc_sanitize_packet(IPC_MSG* pckt) + { + if (!pckt || + !ipc_int_sanitize_packet(pckt)) + { + return false; + } + + return true; + } + + /// @brief Construct packet function + /// @retval true packet is correct. + /// @retval false packet is incorrect and process has crashed. + Bool ipc_construct_packet(_Output IPC_MSG** pckt_in) + { + // don't act if it's not even valid. + if (!pckt_in) + return false; + + if (!*pckt_in) + *pckt_in = new IPC_MSG(); + + MUST_PASS(*pckt_in); + + if (*pckt_in) + { + const auto endianess = RTL_ENDIAN((*pckt_in), ((Char*)(*pckt_in))[0]); + + (*pckt_in)->IpcHeaderMagic = kIPCHeaderMagic; + + (*pckt_in)->IpcEndianess = static_cast<UInt8>(endianess); + (*pckt_in)->IpcPacketSize = sizeof(IPC_MSG); + + (*pckt_in)->IpcTo.UserProcessID = 0; + (*pckt_in)->IpcTo.UserProcessTeam = 0; + + (*pckt_in)->IpcFrom.UserProcessID = 0; + (*pckt_in)->IpcFrom.UserProcessTeam = 0; + + return Yes; + } + + return No; + } + + /// @brief Pass message from **src** to **target** + /// @param src Source message. + /// @param target Target message. + Bool IPC_MSG::Pass(IPC_MSG* src, IPC_MSG* target) noexcept + { + if (src && target && (target != src)) + { + if (src->IpcMsgSz > target->IpcMsgSz) + return No; + + if (target->IpcMsgSz > src->IpcMsgSz) + return No; + + rt_copy_memory(src->IpcData, target->IpcData, src->IpcMsgSz); + + return Yes; + } + + return No; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/MACAddressGetter.cc b/dev/kernel/src/Network/MACAddressGetter.cc new file mode 100644 index 00000000..627bcd34 --- /dev/null +++ b/dev/kernel/src/Network/MACAddressGetter.cc @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/MAC.h> + +namespace NeOS +{ + Array<WideChar, kMACAddrLen>& MacAddressGetter::AsBytes() + { + return this->fMacAddress; + } +} // namespace NeOS diff --git a/dev/kernel/src/Network/NetworkDevice.cc b/dev/kernel/src/Network/NetworkDevice.cc new file mode 100644 index 00000000..f2971265 --- /dev/null +++ b/dev/kernel/src/Network/NetworkDevice.cc @@ -0,0 +1,35 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NetworkKit/NetworkDevice.h> +#include <NewKit/Utils.h> + +namespace NeOS +{ + /// \brief Getter for fNetworkName. + const Char* NetworkDevice::Name() const + { + return this->fNetworkName; + } + + /// \brief Setter for fNetworkName. + Boolean NetworkDevice::Name(const Char* devnam) + { + if (devnam == nullptr) + return NO; + + if (*devnam == 0) + return NO; + + if (rt_string_len(devnam) > cNetworkNameLen) + return NO; + + rt_copy_memory((VoidPtr)devnam, + (VoidPtr)this->fNetworkName, rt_string_len(devnam)); + + return YES; + } +} // namespace NeOS diff --git a/dev/kernel/src/New+Delete.cc b/dev/kernel/src/New+Delete.cc new file mode 100644 index 00000000..1e0a3421 --- /dev/null +++ b/dev/kernel/src/New+Delete.cc @@ -0,0 +1,50 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/MemoryMgr.h> +#include <NewKit/New.h> + +void* operator new[](size_t sz) +{ + if (sz == 0) + ++sz; + + return NeOS::mm_new_heap(sz, true, false); +} + +void* operator new(size_t sz) +{ + if (sz == 0) + ++sz; + + return NeOS::mm_new_heap(sz, true, false); +} + +void operator delete[](void* ptr) +{ + if (ptr == nullptr) + return; + + NeOS::mm_delete_heap(ptr); +} + +void operator delete(void* ptr) +{ + if (ptr == nullptr) + return; + + NeOS::mm_delete_heap(ptr); +} + +void operator delete(void* ptr, size_t sz) +{ + if (ptr == nullptr) + return; + + NE_UNUSED(sz); + + NeOS::mm_delete_heap(ptr); +} diff --git a/dev/kernel/src/OwnPtr.cc b/dev/kernel/src/OwnPtr.cc new file mode 100644 index 00000000..e4d529aa --- /dev/null +++ b/dev/kernel/src/OwnPtr.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/OwnPtr.h> diff --git a/dev/kernel/src/PEFCodeMgr.cc b/dev/kernel/src/PEFCodeMgr.cc new file mode 100644 index 00000000..426a1e26 --- /dev/null +++ b/dev/kernel/src/PEFCodeMgr.cc @@ -0,0 +1,268 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <KernelKit/MemoryMgr.h> +#include <KernelKit/PEFCodeMgr.h> +#include <KernelKit/UserProcessScheduler.h> +#include <NewKit/Defines.h> +#include <NewKit/KernelPanic.h> +#include <NewKit/OwnPtr.h> +#include <NewKit/KString.h> + +/// @brief PEF stack size symbol. +#define kPefStackSizeSymbol "__PEFSizeOfReserveStack" +#define kPefHeapSizeSymbol "__PEFSizeOfReserveHeap" +#define kPefNameSymbol "__PEFProgramName" + +namespace NeOS +{ + namespace Detail + { + /***********************************************************************************/ + /// @brief Get the PEF platform signature according to the compiled architecture. + /***********************************************************************************/ + UInt32 ldr_get_platform(void) noexcept + { +#if defined(__NE_32X0__) + return kPefArch32x0; +#elif defined(__NE_64X0__) + return kPefArch64x0; +#elif defined(__NE_AMD64__) + return kPefArchAMD64; +#elif defined(__NE_PPC64__) + return kPefArchPowerPC; +#elif defined(__NE_ARM64__) + return kPefArchARM64; +#else + return kPefArchInvalid; +#endif // __32x0__ || __64x0__ || __x86_64__ + } + } // namespace Detail + + /***********************************************************************************/ + /// @brief PEF loader constructor w/ blob. + /// @param blob file blob. + /***********************************************************************************/ + PEFLoader::PEFLoader(const VoidPtr blob) + : fCachedBlob(blob) + { + MUST_PASS(fCachedBlob); + fBad = false; + } + + /***********************************************************************************/ + /// @brief PEF loader constructor. + /// @param path the filesystem path. + /***********************************************************************************/ + PEFLoader::PEFLoader(const Char* path) + : fCachedBlob(nullptr), fBad(false), fFatBinary(false) + { + fFile.New(const_cast<Char*>(path), kRestrictRB); + fPath = KStringBuilder::Construct(path).Leak(); + + auto kPefHeader = "PEF_CONTAINER"; + + fCachedBlob = fFile->Read(kPefHeader, mib_cast(16)); + + PEFContainer* container = reinterpret_cast<PEFContainer*>(fCachedBlob); + + if (container->Cpu == Detail::ldr_get_platform() && + container->Magic[0] == kPefMagic[0] && + container->Magic[1] == kPefMagic[1] && + container->Magic[2] == kPefMagic[2] && + container->Magic[3] == kPefMagic[3] && + container->Magic[4] == kPefMagic[4] && container->Abi == kPefAbi) + { + return; + } + else if (container->Magic[4] == kPefMagic[0] && + container->Magic[3] == kPefMagic[1] && + container->Magic[2] == kPefMagic[2] && + container->Magic[1] == kPefMagic[3] && + container->Magic[0] == kPefMagic[4] && container->Abi == kPefAbi) + { + /// This is a fat binary. + this->fFatBinary = true; + return; + } + + fBad = true; + + if (fCachedBlob) + mm_delete_heap(fCachedBlob); + + kout << "PEFLoader: warn: Executable format error!\r"; + + fCachedBlob = nullptr; + } + + /***********************************************************************************/ + /// @brief PEF destructor. + /***********************************************************************************/ + PEFLoader::~PEFLoader() + { + if (fCachedBlob) + mm_delete_heap(fCachedBlob); + + fFile.Delete(); + } + + /***********************************************************************************/ + /// @brief Finds the symbol according to it's name. + /// @param name name of symbol. + /// @param kind kind of symbol we want. + /***********************************************************************************/ + VoidPtr PEFLoader::FindSymbol(const Char* name, Int32 kind) + { + if (!fCachedBlob || fBad || !name) + return nullptr; + + PEFContainer* container = reinterpret_cast<PEFContainer*>(fCachedBlob); + + auto blob = fFile->Read(name, mib_cast(16)); + + PEFCommandHeader* container_header = reinterpret_cast<PEFCommandHeader*>(blob); + + constexpr auto cMangleCharacter = '$'; + const Char* cContainerKinds[] = {".code64", ".data64", ".zero64", nullptr}; + + ErrorOr<KString> error_or_symbol; + + switch (kind) + { + case kPefCode: { + error_or_symbol = KStringBuilder::Construct(cContainerKinds[0]); // code symbol. + break; + } + case kPefData: { + error_or_symbol = KStringBuilder::Construct(cContainerKinds[1]); // data symbol. + break; + } + case kPefZero: { + error_or_symbol = KStringBuilder::Construct(cContainerKinds[2]); // block starting symbol. + break; + } + default: + return nullptr; // prevent that from the kernel's mode perspective, let that happen if it were + // a user process. + } + + Char* unconst_symbol = const_cast<Char*>(name); + + for (SizeT i = 0UL; i < rt_string_len(unconst_symbol, kPefNameLen); ++i) + { + if (unconst_symbol[i] == ' ') + { + unconst_symbol[i] = cMangleCharacter; + } + } + + error_or_symbol.Leak().Leak() += name; + + for (SizeT index = 0; index < container->Count; ++index) + { + if (KStringBuilder::Equals(container_header->Name, + error_or_symbol.Leak().Leak().CData())) + { + if (container_header->Kind == kind) + { + if (container_header->Cpu != Detail::ldr_get_platform()) + { + if (!this->fFatBinary) + { + mm_delete_heap(blob); + return nullptr; + } + } + + Char* container_blob_value = new Char[container_header->Size]; + + rt_copy_memory((VoidPtr)((Char*)blob + sizeof(PEFCommandHeader)), container_blob_value, container_header->Size); + mm_delete_heap(blob); + + kout << "PEFLoader: INFO: Load stub: " << container_header->Name << "!\r"; + + return container_blob_value; + } + } + } + + mm_delete_heap(blob); + return nullptr; + } + + /// @brief Finds the executable entrypoint. + /// @return + ErrorOr<VoidPtr> PEFLoader::FindStart() + { + if (auto sym = this->FindSymbol(kPefStart, kPefCode); sym) + return ErrorOr<VoidPtr>(sym); + + return ErrorOr<VoidPtr>(kErrorExecutable); + } + + /// @brief Tells if the executable is loaded or not. + /// @return + bool PEFLoader::IsLoaded() noexcept + { + return !fBad && fCachedBlob; + } + + const Char* PEFLoader::Path() + { + return fPath.Leak().CData(); + } + + const Char* PEFLoader::AsString() + { +#ifdef __32x0__ + return "32x0 PEF executable."; +#elif defined(__64x0__) + return "64x0 PEF executable."; +#elif defined(__x86_64__) + return "x86_64 PEF executable."; +#elif defined(__aarch64__) + return "AARCH64 PEF executable."; +#elif defined(__powerpc64__) + return "POWER64 PEF executable."; +#else + return "???? PEF executable."; +#endif // __32x0__ || __64x0__ || __x86_64__ || __powerpc64__ + } + + const Char* PEFLoader::MIME() + { + return kPefApplicationMime; + } + + ErrorOr<VoidPtr> PEFLoader::GetBlob() + { + return ErrorOr<VoidPtr>{this->fCachedBlob}; + } + + namespace Utils + { + ProcessID rtl_create_process(PEFLoader& exec, const Int32& process_kind) noexcept + { + auto errOrStart = exec.FindStart(); + + if (errOrStart.Error() != kErrorSuccess) + return kProcessInvalidID; + + auto id = UserProcessScheduler::The().Spawn(reinterpret_cast<const Char*>(exec.FindSymbol(kPefNameSymbol, kPefData)), errOrStart.Leak().Leak(), exec.GetBlob().Leak().Leak()); + + if (id != kProcessInvalidID) + { + UserProcessScheduler::The().CurrentTeam().AsArray()[id].Kind = process_kind; + UserProcessScheduler::The().CurrentTeam().AsArray()[id].StackSize = *(UIntPtr*)exec.FindSymbol(kPefStackSizeSymbol, kPefData); + UserProcessScheduler::The().CurrentTeam().AsArray()[id].MemoryLimit = *(UIntPtr*)exec.FindSymbol(kPefHeapSizeSymbol, kPefData); + } + + return id; + } + } // namespace Utils +} // namespace NeOS diff --git a/dev/kernel/src/PRDT.cc b/dev/kernel/src/PRDT.cc new file mode 100644 index 00000000..9ea3e70b --- /dev/null +++ b/dev/kernel/src/PRDT.cc @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/KString.h> +#include <StorageKit/PRDT.h> + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief constructs a new PRD. + /// @param prd PRD reference. + /// @note This doesnt construct a valid, please fill it by yourself. + /***********************************************************************************/ + void construct_prdt(Ref<PRDT>& prd) + { + prd.Leak().fPhysAddress = 0x0; + prd.Leak().fSectorCount = 0x0; + prd.Leak().fEndBit = 0x0; + } +} // namespace NeOS diff --git a/dev/kernel/src/PageMgr.cc b/dev/kernel/src/PageMgr.cc new file mode 100644 index 00000000..eb7c7e03 --- /dev/null +++ b/dev/kernel/src/PageMgr.cc @@ -0,0 +1,110 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/PageMgr.h> + +#ifdef __NE_AMD64__ +#include <HALKit/AMD64/Paging.h> +#elif defined(__NE_ARM64__) +#include <HALKit/ARM64/Paging.h> +#endif // ifdef __NE_AMD64__ || defined(__NE_ARM64__) + +namespace NeOS +{ + PTEWrapper::PTEWrapper(Boolean Rw, Boolean User, Boolean ExecDisable, UIntPtr VirtAddr) + : fRw(Rw), + fUser(User), + fExecDisable(ExecDisable), + fVirtAddr(VirtAddr), + fCache(false), + fShareable(false), + fWt(false), + fPresent(true), + fAccessed(false) + { + } + + PTEWrapper::~PTEWrapper() = default; + + /// @brief Flush virtual address. + /// @param VirtAddr + Void PageMgr::FlushTLB() + { +#ifndef __NE_MINIMAL_OS__ + hal_flush_tlb(); +#endif // !__NE_MINIMAL_OS__ + } + + /// @brief Reclaim freed page. + /// @return + Bool PTEWrapper::Reclaim() + { + if (!this->fPresent) + { + this->fPresent = true; + return true; + } + + return false; + } + + /// @brief Request a PTE. + /// @param Rw r/w? + /// @param User user mode? + /// @param ExecDisable disable execution on page? + /// @return + PTEWrapper PageMgr::Request(Boolean Rw, Boolean User, Boolean ExecDisable, SizeT Sz) + { + // Store PTE wrapper right after PTE. + VoidPtr ptr = NeOS::HAL::mm_alloc_bitmap(Rw, User, Sz, false); + + return PTEWrapper{Rw, User, ExecDisable, reinterpret_cast<UIntPtr>(ptr)}; + } + + /// @brief Disable BitMap. + /// @param wrapper the wrapper. + /// @return If the page bitmap was cleared or not. + Bool PageMgr::Free(Ref<PTEWrapper>& wrapper) + { + if (!NeOS::HAL::mm_free_bitmap((VoidPtr)wrapper.Leak().VirtualAddress())) + return false; + + return true; + } + + /// @brief Virtual PTE address. + /// @return The virtual address of the page. + const UIntPtr PTEWrapper::VirtualAddress() + { + return (fVirtAddr); + } + + Bool PTEWrapper::Shareable() + { + return fShareable; + } + + Bool PTEWrapper::Present() + { + return fPresent; + } + + Bool PTEWrapper::Access() + { + return fAccessed; + } + + Void PTEWrapper::NoExecute(const bool enable) + { + fExecDisable = enable; + } + + Bool PTEWrapper::NoExecute() + { + return fExecDisable; + } +} // namespace NeOS diff --git a/dev/kernel/src/Pmm.cc b/dev/kernel/src/Pmm.cc new file mode 100644 index 00000000..b3d5e79e --- /dev/null +++ b/dev/kernel/src/Pmm.cc @@ -0,0 +1,98 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/DebugOutput.h> +#include <NewKit/Pmm.h> + +#if defined(__NE_ARM64__) +#include <HALKit/ARM64/Processor.h> +#endif // defined(__NE_ARM64__) + +#if defined(__NE_AMD64__) +#include <HALKit/AMD64/Processor.h> +#endif // defined(__NE_AMD64__) + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Pmm constructor. + /***********************************************************************************/ + Pmm::Pmm() + : fPageMgr() + { + kout << "[PMM] Allocate PageMemoryMgr"; + } + + Pmm::~Pmm() = default; + + /***********************************************************************************/ + /// @param If this returns Null pointer, enter emergency mode. + /// @param user is this a user page? + /// @param readWrite is it r/w? + /***********************************************************************************/ + Ref<PTEWrapper> Pmm::RequestPage(Boolean user, Boolean readWrite) + { + PTEWrapper pt = fPageMgr.Leak().Request(user, readWrite, false, kPageSize); + + if (pt.fPresent) + { + kout << "[PMM]: Allocation failed.\r"; + return {}; + } + + return Ref<PTEWrapper>(pt); + } + + Boolean Pmm::FreePage(Ref<PTEWrapper> PageRef) + { + if (!PageRef) + return false; + + PageRef.Leak().fPresent = false; + + return true; + } + + Boolean Pmm::TogglePresent(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fPresent = Enable; + + return true; + } + + Boolean Pmm::ToggleUser(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fRw = Enable; + + return true; + } + + Boolean Pmm::ToggleRw(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fRw = Enable; + + return true; + } + + Boolean Pmm::ToggleShare(Ref<PTEWrapper> PageRef, Boolean Enable) + { + if (!PageRef) + return false; + + PageRef.Leak().fShareable = Enable; + + return true; + } +} // namespace NeOS diff --git a/dev/kernel/src/Property.cc b/dev/kernel/src/Property.cc new file mode 100644 index 00000000..8f3b5314 --- /dev/null +++ b/dev/kernel/src/Property.cc @@ -0,0 +1,45 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <CFKit/Property.h> + +namespace CFKit +{ + /***********************************************************************************/ + /// @brief Destructor. + /***********************************************************************************/ + Property::~Property() = default; + + /***********************************************************************************/ + /// @brief Constructor. + /***********************************************************************************/ + Property::Property() = default; + + /***********************************************************************************/ + /// @brief Check if property's name equals to name. + /// @param name string to check. + /***********************************************************************************/ + Bool Property::StringEquals(KString& name) + { + return this->fName && this->fName == name; + } + + /***********************************************************************************/ + /// @brief Gets the key (name) of property. + /***********************************************************************************/ + KString& Property::GetKey() + { + return this->fName; + } + + /***********************************************************************************/ + /// @brief Gets the value of the property. + /***********************************************************************************/ + PropertyId& Property::GetValue() + { + return fValue; + } +} // namespace CFKit diff --git a/dev/kernel/src/Ref.cc b/dev/kernel/src/Ref.cc new file mode 100644 index 00000000..6fadb033 --- /dev/null +++ b/dev/kernel/src/Ref.cc @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Ref.h> diff --git a/dev/kernel/src/SoftwareTimer.cc b/dev/kernel/src/SoftwareTimer.cc new file mode 100644 index 00000000..5e4214e9 --- /dev/null +++ b/dev/kernel/src/SoftwareTimer.cc @@ -0,0 +1,39 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/Timer.h> + +/// @brief SoftwareTimer class, meant to be generic. + +using namespace NeOS; + +SoftwareTimer::SoftwareTimer(Int64 seconds) + : fWaitFor(seconds) +{ + fDigitalTimer = new IntPtr(); + MUST_PASS(fDigitalTimer); +} + +SoftwareTimer::~SoftwareTimer() +{ + delete fDigitalTimer; + fDigitalTimer = nullptr; + + fWaitFor = 0; +} + +BOOL SoftwareTimer::Wait() noexcept +{ + if (fWaitFor < 1) + return NO; + + while (*fDigitalTimer < (*fDigitalTimer + fWaitFor)) + { + ++(*fDigitalTimer); + } + + return YES; +} diff --git a/dev/kernel/src/Storage/AHCIDeviceInterface.cc b/dev/kernel/src/Storage/AHCIDeviceInterface.cc new file mode 100644 index 00000000..8d987ab5 --- /dev/null +++ b/dev/kernel/src/Storage/AHCIDeviceInterface.cc @@ -0,0 +1,36 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/AHCI.h> + +using namespace NeOS; + +/// @brief Class constructor +/// @param Out Drive output +/// @param In Drive input +/// @param Cleanup Drive cleanup. +AHCIDeviceInterface::AHCIDeviceInterface(void (*out)(IDeviceObject* self, MountpointInterface* outpacket), + void (*in)(IDeviceObject* self, MountpointInterface* inpacket), + void (*cleanup)(void)) + : IDeviceObject(out, in), fCleanup(cleanup) +{ +} + +/// @brief Class desctructor +AHCIDeviceInterface::~AHCIDeviceInterface() +{ + MUST_PASS(fCleanup); + + if (fCleanup) + fCleanup(); +} + +/// @brief Returns the name of the device interface. +/// @return it's name as a string. +const Char* AHCIDeviceInterface::Name() const +{ + return "/dev/sda{}"; +} diff --git a/dev/kernel/src/Storage/ATADeviceInterface.cc b/dev/kernel/src/Storage/ATADeviceInterface.cc new file mode 100644 index 00000000..9f1a0068 --- /dev/null +++ b/dev/kernel/src/Storage/ATADeviceInterface.cc @@ -0,0 +1,88 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/ATA.h> + +using namespace NeOS; + +/// @brief Class constructor +/// @param Out Drive output +/// @param In Drive input +/// @param Cleanup Drive cleanup. +ATADeviceInterface::ATADeviceInterface( + void (*Out)(IDeviceObject*, MountpointInterface* outpacket), + void (*In)(IDeviceObject*, MountpointInterface* inpacket), + void (*Cleanup)(void)) + : IDeviceObject(Out, In), fCleanup(Cleanup) +{ +} + +/// @brief Class desctructor +ATADeviceInterface::~ATADeviceInterface() +{ + MUST_PASS(fCleanup); + if (fCleanup) + fCleanup(); +} + +/// @brief Returns the name of the device interface. +/// @return it's name as a string. +const Char* ATADeviceInterface::Name() const +{ + return "/dev/hda{}"; +} + +/// @brief Output operator. +/// @param Data +/// @return +ATADeviceInterface& ATADeviceInterface::operator<<(MountpointInterface* Data) +{ + if (!Data) + return *this; + + for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) + { + auto interface = Data->GetAddressOf(driveCount); + if ((interface) && rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) == 0) + { + continue; + } + else if ((interface) && + rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) != 0) + { + return *this; + } + } + + return (ATADeviceInterface&)IDeviceObject<MountpointInterface*>::operator<<( + Data); +} + +/// @brief Input operator. +/// @param Data +/// @return +ATADeviceInterface& ATADeviceInterface::operator>>(MountpointInterface* Data) +{ + if (!Data) + return *this; + + for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) + { + auto interface = Data->GetAddressOf(driveCount); + if ((interface) && rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) == 0) + { + continue; + } + else if ((interface) && + rt_string_cmp((interface)->fDriveKind(), "ATA-", 5) != 0) + { + return *this; + } + } + + return (ATADeviceInterface&)IDeviceObject<MountpointInterface*>::operator>>( + Data); +} diff --git a/dev/kernel/src/Storage/NVMEDeviceInterface.cc b/dev/kernel/src/Storage/NVMEDeviceInterface.cc new file mode 100644 index 00000000..3e2c2c53 --- /dev/null +++ b/dev/kernel/src/Storage/NVMEDeviceInterface.cc @@ -0,0 +1,28 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/NVME.h> + +namespace NeOS +{ + NVMEDeviceInterface::NVMEDeviceInterface(void (*out)(IDeviceObject*, MountpointInterface* outpacket), + void (*in)(IDeviceObject*, MountpointInterface* inpacket), + void (*cleanup)(void)) + : IDeviceObject(out, in), fCleanup(cleanup) + { + } + + NVMEDeviceInterface::~NVMEDeviceInterface() + { + if (fCleanup) + fCleanup(); + } + + const Char* NVMEDeviceInterface::Name() const + { + return ("/dev/nvme{}"); + } +} // namespace NeOS diff --git a/dev/kernel/src/Storage/SCSIDeviceInterface.cc b/dev/kernel/src/Storage/SCSIDeviceInterface.cc new file mode 100644 index 00000000..cc625cdb --- /dev/null +++ b/dev/kernel/src/Storage/SCSIDeviceInterface.cc @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <StorageKit/SCSI.h> + +///! @brief ATAPI SCSI packet. +const scsi_packet_type<12> kCDRomPacketTemplate = {0x43, 0, 1, 0, 0, 0, + 0, 12, 0x40, 0, 0}; diff --git a/dev/kernel/src/Stream.cc b/dev/kernel/src/Stream.cc new file mode 100644 index 00000000..8d060556 --- /dev/null +++ b/dev/kernel/src/Stream.cc @@ -0,0 +1,12 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + File: Stream.cc + Purpose: Stream object + + Revision History: + +------------------------------------------- */ + +#include <NewKit/Stream.h> diff --git a/dev/kernel/src/System/SwapDisk.cc b/dev/kernel/src/System/SwapDisk.cc new file mode 100644 index 00000000..921ea86d --- /dev/null +++ b/dev/kernel/src/System/SwapDisk.cc @@ -0,0 +1,47 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss Labs, all rights reserved. + +------------------------------------------- */ + +#include <SystemKit/SwapDisk.h> +#include <KernelKit/FileMgr.h> + +namespace NeOS +{ + BOOL SwapDisk::Write(const Char* fork_name, const SizeT fork_name_len, SWAP_DISK_HEADER* data, const SizeT data_len) + { + if (!fork_name || !fork_name_len) + return NO; + + if (data_len > kSwapBlockMaxSize) + return NO; + + if (!data) + return NO; + + FileStream file(kSwapPageFile, "wb"); + + auto ret = file.Write(fork_name, data, sizeof(SWAP_DISK_HEADER) + data_len); + + if (ret.Error()) + return NO; + + return YES; + } + + SWAP_DISK_HEADER* SwapDisk::Read(const Char* fork_name, const SizeT fork_name_len, const SizeT data_len) + { + if (!fork_name || !fork_name_len) + return nullptr; + + if (data_len > kSwapBlockMaxSize) + return nullptr; + + FileStream file(kSwapPageFile, "rb"); + + VoidPtr blob = file.Read(fork_name, sizeof(SWAP_DISK_HEADER) + data_len); + + return (SWAP_DISK_HEADER*)blob; + } +} // namespace NeOS diff --git a/dev/kernel/src/ThreadLocalStorage.cc b/dev/kernel/src/ThreadLocalStorage.cc new file mode 100644 index 00000000..b25b4288 --- /dev/null +++ b/dev/kernel/src/ThreadLocalStorage.cc @@ -0,0 +1,67 @@ +/* + * ======================================================== + * + * neoskrnl + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#include <NewKit/KString.h> +#include <CFKit/Property.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/ThreadLocalStorage.h> + +/***********************************************************************************/ +/// @bugs: 0 +/// @file ThreadLocalStorage.cc +/// @brief Process Thread Local Storage. +/***********************************************************************************/ + +using namespace NeOS; + +/** + * @brief Checks for cookie inside the TIB. + * @param tib_ptr the TIB to check. + * @return if the cookie is enabled, true; false otherwise + */ + +Boolean tls_check_tib(THREAD_INFORMATION_BLOCK* tib_ptr) +{ + if (!tib_ptr || + !tib_ptr->Record) + return false; + + ICodec encoder; + const Char* tib_as_bytes = encoder.AsBytes(tib_ptr); + + kout << "TLS: Validating the TIB...\r"; + + return tib_as_bytes[kCookieMag0Idx] == kCookieMag0 && tib_as_bytes[kCookieMag1Idx] == kCookieMag1 && + tib_as_bytes[kCookieMag2Idx] == kCookieMag2; +} + +/** + * @brief System call implementation of the TLS check. + * @param tib_ptr The TIB record. + * @return if the TIB record is valid or not. + */ +EXTERN_C Bool tls_check_syscall_impl(NeOS::VoidPtr tib_ptr) noexcept +{ + if (!tib_ptr) + { + kout << "TLS: Failed because of an invalid TIB...\r"; + return No; + } + + THREAD_INFORMATION_BLOCK* tib = reinterpret_cast<THREAD_INFORMATION_BLOCK*>(tib_ptr); + + if (!tls_check_tib(tib)) + { + kout << "TLS: Failed because of an invalid TIB...\r"; + return No; + } + + kout << "TLS Pass.\r"; + return Yes; +} diff --git a/dev/kernel/src/Timer.cc b/dev/kernel/src/Timer.cc new file mode 100644 index 00000000..5df81134 --- /dev/null +++ b/dev/kernel/src/Timer.cc @@ -0,0 +1,19 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <KernelKit/Timer.h> + +///! BUGS: 0 +///! @file Timer.cc +///! @brief Software Timer implementation + +using namespace NeOS; + +/// @brief Unimplemented as it is an interface. +BOOL TimerInterface::Wait() noexcept +{ + return NO; +} diff --git a/dev/kernel/src/User.cc b/dev/kernel/src/User.cc new file mode 100644 index 00000000..3c23c59e --- /dev/null +++ b/dev/kernel/src/User.cc @@ -0,0 +1,195 @@ +/* + * ======================================================== + * + * NeKernel + * Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + * + * File: User.cc + * Purpose: User class, used to provide authentication and security. + * + * ======================================================== + */ + +#include <KernelKit/User.h> +#include <KernelKit/LPC.h> +#include <NewKit/KernelPanic.h> +#include <KernelKit/FileMgr.h> +#include <KernelKit/MemoryMgr.h> + +#define kStdUserType (0xEE) +#define kSuperUserType (0xEF) + +/// @file User.cc +/// @brief Multi-user support. + +namespace NeOS +{ + namespace Detail + { + //////////////////////////////////////////////////////////// + /// \brief Constructs a password by hashing the password. + /// \param password password to hash. + /// \return the hashed password + //////////////////////////////////////////////////////////// + const Int32 cred_construct_token(Char* password, const Char* in_password, User* user, SizeT length) + { + if (!password || !user) + return 1; + + kout << "cred_construct_token: Hashing user password...\r"; + + for (SizeT i_pass = 0UL; i_pass < length; ++i_pass) + { + const Char cur_chr = in_password[i_pass]; + + if (cur_chr == 0) + break; + + password[i_pass] = cur_chr | (user->IsStdUser() ? kStdUserType : kSuperUserType); + } + + kout << "cred_construct_token: Hashed user password.\r"; + + return 0; + } + } // namespace Detail + + //////////////////////////////////////////////////////////// + /// @brief User ring constructor. + //////////////////////////////////////////////////////////// + User::User(const Int32& sel, const Char* user_name) + : mUserRing((UserRingKind)sel) + { + MUST_PASS(sel >= 0); + rt_copy_memory((VoidPtr)user_name, this->mUserName, rt_string_len(user_name)); + } + + //////////////////////////////////////////////////////////// + /// @brief User ring constructor. + //////////////////////////////////////////////////////////// + User::User(const UserRingKind& ring_kind, const Char* user_name) + : mUserRing(ring_kind) + { + rt_copy_memory((VoidPtr)user_name, this->mUserName, rt_string_len(user_name)); + } + + //////////////////////////////////////////////////////////// + /// @brief User destructor class. + //////////////////////////////////////////////////////////// + User::~User() = default; + + Bool User::Save(const UserPublicKey password_to_fill) noexcept + { + if (!password_to_fill || + *password_to_fill == 0) + return No; + + SizeT len = rt_string_len(password_to_fill); + + UserPublicKey password = new UserPublicKeyType[len]; + + MUST_PASS(password); + + rt_set_memory(password, 0, len); + + // fill data first, generate hash. + // return false on error. + + rt_copy_memory((VoidPtr)password_to_fill, password, len); + + if (!Detail::cred_construct_token(password, password_to_fill, this, len)) + { + delete[] password; + password = nullptr; + + return No; + } + + // then store password. + + rt_copy_memory(password, this->mUserKey, rt_string_len(password_to_fill)); + + delete[] password; + password = nullptr; + + kout << "User::Save: Saved password successfully...\r"; + + return Yes; + } + + Bool User::Matches(const UserPublicKey password_to_fill) noexcept + { + if (!password_to_fill || + *password_to_fill) + return No; + + SizeT len = rt_string_len(password_to_fill); + + Char* password = new Char[len]; + MUST_PASS(password); + + // fill data first, generate hash. + // return false on error. + + rt_copy_memory((VoidPtr)password_to_fill, password, len); + + if (!Detail::cred_construct_token(password, password_to_fill, this, len)) + { + delete[] password; + password = nullptr; + + return No; + } + + kout << "User::Matches: Validating hashed passwords...\r"; + + // now check if the password matches. + if (rt_string_cmp(password, this->mUserKey, rt_string_len(this->mUserKey)) == 0) + { + kout << "User::Matches: Password matches.\r"; + return Yes; + } + + kout << "User::Matches: Password doesn't match.\r"; + return No; + } + + Bool User::operator==(const User& lhs) + { + return lhs.mUserRing == this->mUserRing; + } + + Bool User::operator!=(const User& lhs) + { + return lhs.mUserRing != this->mUserRing; + } + + //////////////////////////////////////////////////////////// + /// @brief Returns the user's name. + //////////////////////////////////////////////////////////// + + Char* User::Name() noexcept + { + return this->mUserName; + } + + //////////////////////////////////////////////////////////// + /// @brief Returns the user's ring. + /// @return The king of ring the user is attached to. + //////////////////////////////////////////////////////////// + + const UserRingKind& User::Ring() noexcept + { + return this->mUserRing; + } + + Bool User::IsStdUser() noexcept + { + return this->Ring() == UserRingKind::kRingStdUser; + } + + Bool User::IsSuperUser() noexcept + { + return this->Ring() == UserRingKind::kRingSuperUser; + } +} // namespace NeOS diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc new file mode 100644 index 00000000..1087ac6b --- /dev/null +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -0,0 +1,621 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + + FILE: UserProcessScheduler.cc + PURPOSE: Low level/Ring-3 Process scheduler. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file UserProcessScheduler.cc +/// @brief Low level/Ring-3 process scheduler. +/***********************************************************************************/ + +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/HardwareThreadScheduler.h> +#include <KernelKit/IPEFDylibObject.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/MemoryMgr.h> +#include <NewKit/KString.h> +#include <KernelKit/LPC.h> + +///! BUGS: 0 + +namespace NeOS +{ + /***********************************************************************************/ + /// @brief Exit Code global variable. + /***********************************************************************************/ + + STATIC UInt32 kLastExitCode = 0U; + + /***********************************************************************************/ + /// @brief External reference of the thread scheduler. + /***********************************************************************************/ + + STATIC UserProcessScheduler kProcessScheduler; + + UserProcess::UserProcess() = default; + UserProcess::~UserProcess() = default; + + /// @brief Gets the last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + + const UInt32& sched_get_exit_code(void) noexcept + { + return kLastExitCode; + } + + /***********************************************************************************/ + /// @brief Crashes the current process. + /***********************************************************************************/ + + Void UserProcess::Crash() + { + if (this->Status != ProcessStatusKind::kRunning) + return; + + kout << this->Name << ": crashed, error id: " << number(kErrorProcessFault) << kendl; + this->Exit(kErrorProcessFault); + } + + /***********************************************************************************/ + /// @brief boolean operator, check status. + /***********************************************************************************/ + + UserProcess::operator bool() + { + return this->Status == ProcessStatusKind::kRunning; + } + + /***********************************************************************************/ + /// @brief Gets the local last exit code. + /// @note Not thread-safe. + /// @return Int32 the last exit code. + /***********************************************************************************/ + + const UInt32& UserProcess::GetExitCode() noexcept + { + return this->fLastExitCode; + } + + /***********************************************************************************/ + /// @brief Error code variable getter. + /***********************************************************************************/ + + Int32& UserProcess::GetLocalCode() noexcept + { + return this->fLocalCode; + } + + /***********************************************************************************/ + /// @brief Wakes process header. + /// @param should_wakeup if the program shall wakeup or not. + /***********************************************************************************/ + + Void UserProcess::Wake(const Bool should_wakeup) + { + this->Status = + should_wakeup ? ProcessStatusKind::kRunning : ProcessStatusKind::kFrozen; + } + + /***********************************************************************************/ + /** @brief Allocate pointer to track list. */ + /***********************************************************************************/ + + ErrorOr<VoidPtr> UserProcess::New(const SizeT& sz, const SizeT& pad_amount) + { +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + auto vm_register = hal_read_cr3(); + hal_write_cr3(this->VMRegister); + + auto ptr = mm_new_heap(sz + pad_amount, Yes, Yes); + + hal_write_cr3(vm_register); +#else + auto ptr = mm_new_heap(sz + pad_amount, Yes, Yes); +#endif + + if (!this->ProcessMemoryHeap) + { + this->ProcessMemoryHeap = new ProcessMemoryHeapList(); + + this->ProcessMemoryHeap->MemoryEntryPad = pad_amount; + this->ProcessMemoryHeap->MemoryEntrySize = sz; + + this->ProcessMemoryHeap->MemoryEntry = ptr; + + this->ProcessMemoryHeap->MemoryPrev = nullptr; + this->ProcessMemoryHeap->MemoryNext = nullptr; + } + else + { + ProcessMemoryHeapList* entry = this->ProcessMemoryHeap; + ProcessMemoryHeapList* prev_entry = nullptr; + + while (entry) + { + if (entry->MemoryEntry == nullptr) + break; // chose to break here, when we get an already allocated memory entry for our needs. + + prev_entry = entry; + entry = entry->MemoryNext; + } + + entry->MemoryNext = new ProcessMemoryHeapList(); + entry->MemoryNext->MemoryEntry = ptr; + + entry->MemoryNext->MemoryPrev = entry; + entry->MemoryNext->MemoryNext = nullptr; + } + + this->UsedMemory += sz; + + return ErrorOr<VoidPtr>(ptr); + } + + /***********************************************************************************/ + /// @brief Gets the name of the current process. + /***********************************************************************************/ + + const Char* UserProcess::GetName() noexcept + { + return this->Name; + } + + /***********************************************************************************/ + /// @brief Gets the owner of the process. + /***********************************************************************************/ + + const User* UserProcess::GetOwner() noexcept + { + return this->Owner; + } + + /// @brief UserProcess status getter. + const ProcessStatusKind& UserProcess::GetStatus() noexcept + { + return this->Status; + } + + /***********************************************************************************/ + /** + @brief Affinity is the time slot allowed for the process. + */ + /***********************************************************************************/ + + const AffinityKind& UserProcess::GetAffinity() noexcept + { + return this->Affinity; + } + + /***********************************************************************************/ + /** + @brief Exit process method. + @param exit_code The process's exit code. + */ + /***********************************************************************************/ + + Void UserProcess::Exit(const Int32& exit_code) + { + this->Status = exit_code > 0 ? ProcessStatusKind::kKilled : ProcessStatusKind::kFrozen; + this->fLastExitCode = exit_code; + + kLastExitCode = exit_code; + + auto memory_heap_list = this->ProcessMemoryHeap; + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + auto pd = hal_read_cr3(); + hal_write_cr3(this->VMRegister); +#endif + + // Deleting memory lists. Make sure to free all of them. + while (memory_heap_list) + { + if (memory_heap_list->MemoryEntry) + { + MUST_PASS(mm_delete_heap(memory_heap_list->MemoryEntry)); + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + hal_write_cr3(pd); +#endif + + auto next = memory_heap_list->MemoryNext; + + mm_delete_heap(memory_heap_list); + + memory_heap_list = next; + } + + //! Free the memory's page directory. + HAL::mm_free_bitmap(this->VMRegister); + + //! Delete image if not done already. + if (this->Image.fCode && mm_is_valid_heap(this->Image.fCode)) + mm_delete_heap(this->Image.fCode); + + if (this->Image.fBlob && mm_is_valid_heap(this->Image.fBlob)) + mm_delete_heap(this->Image.fBlob); + + if (this->StackFrame && mm_is_valid_heap(this->StackFrame)) + mm_delete_heap((VoidPtr)this->StackFrame); + + this->Image.fBlob = nullptr; + this->Image.fCode = nullptr; + this->StackFrame = nullptr; + + if (this->Kind == kExectuableDylibKind) + { + Bool success = false; + + rtl_fini_dylib(*this, reinterpret_cast<IPEFDylibObject*>(this->DylibDelegate), &success); + + if (!success) + { + ke_panic(RUNTIME_CHECK_PROCESS); + } + + this->DylibDelegate = nullptr; + } + + if (this->StackReserve) + mm_delete_heap(reinterpret_cast<VoidPtr>(this->StackReserve)); + + this->ProcessId = 0; + this->Status = ProcessStatusKind::kFinished; + + --this->ProcessParentTeam->mProcessCount; + + delete this; + } + + /***********************************************************************************/ + /// @brief Add process to team. + /// @param process the process *Ref* class. + /// @return the process index inside the team. + /***********************************************************************************/ + + ProcessID UserProcessScheduler::Spawn(const Char* name, VoidPtr code, VoidPtr image) + { + ProcessID pid = this->mTeam.mProcessCount; + + if (pid > kSchedProcessLimitPerTeam) + { + return kErrorProcessFault; + } + + ++this->mTeam.mProcessCount; + + UserProcess& process = this->mTeam.mProcessList[pid]; + + process.Image.fCode = code; + process.Image.fBlob = image; + + rt_copy_memory(reinterpret_cast<VoidPtr>(const_cast<Char*>(name)), process.Name, rt_string_len(name)); + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + process.VMRegister = new PDE(); + + if (!process.VMRegister) + { + process.Crash(); + return kErrorProcessFault; + } + + UInt32 flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.VMRegister, process.VMRegister, flags); +#endif // __NE_VIRTUAL_MEMORY_SUPPORT__ + + process.StackFrame = new HAL::StackFrame(); + + if (!process.StackFrame) + { + process.Crash(); + return kErrorProcessFault; + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.StackFrame, process.StackFrame, flags); +#endif // __NE_VIRTUAL_MEMORY_SUPPORT__ + + // React according to process kind. + switch (process.Kind) + { + case UserProcess::kExectuableDylibKind: { + process.DylibDelegate = rtl_init_dylib(process); + MUST_PASS(process.DylibDelegate); + } + default: { + kout << "Unknown process kind: " << hex_number(process.Kind) << kendl; + break; + } + } + + process.StackReserve = new UInt8[process.StackSize]; + rt_set_memory(process.StackReserve, 0, process.StackSize); + + if (!process.StackReserve) + { + process.Crash(); + return kErrorProcessFault; + } + +#ifdef __NE_VIRTUAL_MEMORY_SUPPORT__ + flags = HAL::kMMFlagsPresent; + flags |= HAL::kMMFlagsWr; + flags |= HAL::kMMFlagsUser; + + HAL::mm_map_page((VoidPtr)process.StackReserve, process.StackReserve, flags); +#endif // __NE_VIRTUAL_MEMORY_SUPPORT__ + + process.ProcessParentTeam = &mTeam; + + process.ProcessId = pid; + process.Status = ProcessStatusKind::kStarting; + process.PTime = (UIntPtr)AffinityKind::kStandard; + + kout << "PID: " << number(process.ProcessId) << kendl; + kout << "Name: " << process.Name << kendl; + + return pid; + } + + /***********************************************************************************/ + /// @brief Retrieves the singleton of the process scheduler. + /***********************************************************************************/ + + UserProcessScheduler& UserProcessScheduler::The() + { + return kProcessScheduler; + } + + /***********************************************************************************/ + + /// @brief Remove process from the team. + /// @param process_id process slot inside team. + /// @retval true process was removed. + /// @retval false process doesn't exist in team. + + /***********************************************************************************/ + + const Bool UserProcessScheduler::Remove(ProcessID process_id) + { + // check if process is within range. + if (process_id > mTeam.mProcessList.Count()) + return No; + + mTeam.mProcessList[process_id].Exit(0); + + return Yes; + } + + /// @brief Is it a user scheduler? + + const Bool UserProcessScheduler::IsUser() + { + return Yes; + } + + /// @brief Is it a kernel scheduler? + + const Bool UserProcessScheduler::IsKernel() + { + return No; + } + + /// @brief Is it a SMP scheduler? + + const Bool UserProcessScheduler::HasMP() + { + return Yes; + } + + /***********************************************************************************/ + /// @brief Run User scheduler object. + /// @return Process count executed within a team. + /***********************************************************************************/ + + const SizeT UserProcessScheduler::Run() noexcept + { + SizeT process_index = 0UL; //! we store this guy to tell the scheduler how many + //! things we have scheduled. + + if (mTeam.mProcessCount < 1) + { + kout << "UserProcessScheduler::Run(): This team doesn't have any process!\r"; + return 0UL; + } + for (; process_index < mTeam.AsArray().Capacity(); ++process_index) + { + auto& process = mTeam.AsArray()[process_index]; + + //! check if the process needs to be run. + if (UserProcessHelper::CanBeScheduled(process)) + { + // Set current process header. + this->CurrentProcess() = process; + + process.PTime = static_cast<Int32>(process.Affinity); + + kout << "Switch to: '" << process.Name << "'.\r"; + + // tell helper to find a core to schedule on. + BOOL ret = UserProcessHelper::Switch(process.Image.fCode, &process.StackReserve[process.StackSize - 1], process.StackFrame, + process.ProcessId); + + if (!ret) + { + if (process.Affinity == AffinityKind::kRealTime) + continue; + + kout << "The process: " << process.Name << ", is not valid! Crashing it...\r"; + + process.Crash(); + } + } + else + { + --process.PTime; + } + } + + return process_index; + } + + /// @brief Gets the current scheduled team. + /// @return + UserProcessTeam& UserProcessScheduler::CurrentTeam() + { + return mTeam; + } + + /// @internal + + /// @brief Gets current running process. + /// @return + Ref<UserProcess>& UserProcessScheduler::CurrentProcess() + { + return mTeam.AsRef(); + } + + /// @brief Current proccess id getter. + /// @return UserProcess ID integer. + ErrorOr<PID> UserProcessHelper::TheCurrentPID() + { + if (!kProcessScheduler.CurrentProcess()) + return ErrorOr<PID>{kErrorProcessFault}; + + kout << "UserProcessHelper::TheCurrentPID: Leaking ProcessId...\r"; + return ErrorOr<PID>{kProcessScheduler.CurrentProcess().Leak().ProcessId}; + } + + /// @brief Check if process can be schedulded. + /// @param process the process reference. + /// @retval true can be schedulded. + /// @retval false cannot be schedulded. + Bool UserProcessHelper::CanBeScheduled(const UserProcess& process) + { + if (process.Status == ProcessStatusKind::kKilled || + process.Status == ProcessStatusKind::kFinished || + process.Status == ProcessStatusKind::kStarting || + process.Status == ProcessStatusKind::kFrozen) + return No; + + if (process.Status == ProcessStatusKind::kInvalid) + return No; + + if (!process.Image.fCode) + return No; + + if (!process.Name[0]) + return No; + + // real time processes shouldn't wait that much. + if (process.Affinity == AffinityKind::kRealTime) + return Yes; + + return process.PTime < 1; + } + + /***********************************************************************************/ + /** + * @brief Start scheduling current AP. + */ + /***********************************************************************************/ + + SizeT UserProcessHelper::StartScheduling() + { + return kProcessScheduler.Run(); + } + + /***********************************************************************************/ + /** + * \brief Does a context switch in a CPU. + * \param the_stack the stackframe of the running app. + * \param new_pid the process's PID. + */ + /***********************************************************************************/ + + Bool UserProcessHelper::Switch(VoidPtr image, UInt8* stack, HAL::StackFramePtr frame_ptr, const PID& new_pid) + { + for (SizeT index = 0UL; index < HardwareThreadScheduler::The().Capacity(); ++index) + { + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPInvalid || + HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPBoot) + continue; + + // A fallback is a special core for real-time tasks which needs immediate execution. + if (HardwareThreadScheduler::The()[index].Leak()->Kind() == kAPRealTime) + { + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity != AffinityKind::kRealTime) + continue; + + if (HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid)) + { + PTime prev_ptime = HardwareThreadScheduler::The()[index].Leak()->fPTime; + + HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + + PID prev_pid = UserProcessHelper::TheCurrentPID(); + UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; + + return YES; + } + + continue; + } + + if (UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].Affinity == AffinityKind::kRealTime) + continue; + + //////////////////////////////////////////////////////////// + /// Prepare task switch. /// + //////////////////////////////////////////////////////////// + + Bool ret = HardwareThreadScheduler::The()[index].Leak()->Switch(image, stack, frame_ptr, new_pid); + + //////////////////////////////////////////////////////////// + /// Rollback on fail. /// + //////////////////////////////////////////////////////////// + + if (!ret) + continue; + + UserProcessHelper::TheCurrentPID().Leak().Leak() = new_pid; + + HardwareThreadScheduler::The()[index].Leak()->fPTime = UserProcessScheduler::The().CurrentTeam().AsArray()[new_pid].PTime; + HardwareThreadScheduler::The()[index].Leak()->Wake(YES); + + return Yes; + } + + return No; + } + + //////////////////////////////////////////////////////////// + /// @brief this checks if any process is on the team. + //////////////////////////////////////////////////////////// + UserProcessScheduler::operator bool() + { + return mTeam.AsArray().Count() > 0; + } + + //////////////////////////////////////////////////////////// + /// @brief this checks if no process is on the team. + //////////////////////////////////////////////////////////// + Bool UserProcessScheduler::operator!() + { + return mTeam.AsArray().Count() == 0; + } +} // namespace NeOS diff --git a/dev/kernel/src/UserProcessTeam.cc b/dev/kernel/src/UserProcessTeam.cc new file mode 100644 index 00000000..e0533ef1 --- /dev/null +++ b/dev/kernel/src/UserProcessTeam.cc @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/***********************************************************************************/ +/// @file UserProcessTeam.cc +/// @brief Process teams implementation. +/***********************************************************************************/ + +#include <KernelKit/UserProcessScheduler.h> + +namespace NeOS +{ + UserProcessTeam::UserProcessTeam() + { + for (SizeT i = 0U; i < this->mProcessList.Count(); ++i) + { + this->mProcessList[i] = UserProcess(); + this->mProcessList[i].PTime = 0; + this->mProcessList[i].Status = ProcessStatusKind::kKilled; + } + + this->mProcessCount = 0UL; + } + + /***********************************************************************************/ + /// @brief UserProcess list array getter. + /// @return The list of process to schedule. + /***********************************************************************************/ + + Array<UserProcess, kSchedProcessLimitPerTeam>& UserProcessTeam::AsArray() + { + return this->mProcessList; + } + + /***********************************************************************************/ + /// @brief Get team ID. + /// @return The team's ID. + /***********************************************************************************/ + + ProcessID& UserProcessTeam::Id() noexcept + { + return this->mTeamId; + } + + /***********************************************************************************/ + /// @brief Get current process getter as Ref. + /// @return The current process header. + /***********************************************************************************/ + + Ref<UserProcess>& UserProcessTeam::AsRef() + { + return this->mCurrentProcess; + } +} // namespace NeOS + +// last rev 05-03-24 diff --git a/dev/kernel/src/Utils.cc b/dev/kernel/src/Utils.cc new file mode 100644 index 00000000..a362099a --- /dev/null +++ b/dev/kernel/src/Utils.cc @@ -0,0 +1,224 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Utils.h> + +namespace NeOS +{ + Int32 rt_string_cmp(const Char* src, const Char* cmp, Size size) + { + Int32 counter = 0; + + for (Size index = 0; index < size; ++index) + { + if (src[index] != cmp[index]) + ++counter; + } + + return counter; + } + + Void rt_zero_memory(voidPtr pointer, Size len) + { + rt_set_memory(pointer, 0, len); + } + + SizeT rt_string_len(const Char* str, SizeT _len) + { + SizeT len{0}; + + do + { + if (len > _len) + { + return _len; + } + + ++len; + } while (str[len] != '\0'); + + return len; + } + + Size rt_string_len(const Char* ptr) + { + SizeT cnt{0}; + + while (ptr[cnt] != 0) + ++cnt; + + return cnt; + } + + voidPtr rt_set_memory(voidPtr src, UInt32 value, Size len) + { + UInt32* start = reinterpret_cast<UInt32*>(src); + + while (len) + { + *start = value; + ++start; + --len; + } + + return (voidPtr)start; + } + + Int rt_move_memory(const voidPtr src, voidPtr dst, Size len) + { + Char* srcChr = reinterpret_cast<Char*>(src); + Char* dstChar = reinterpret_cast<Char*>(dst); + SizeT index = 0; + + while (index < len) + { + dstChar[index] = srcChr[index]; + srcChr[index] = 0; + + ++index; + } + + return 0; + } + + Int rt_copy_memory(const voidPtr src, voidPtr dst, Size len) + { + char* srcChr = reinterpret_cast<char*>(src); + char* dstChar = reinterpret_cast<char*>(dst); + Size index = 0; + + while (index < len) + { + dstChar[index] = srcChr[index]; + ++index; + } + + dstChar[index] = 0; + + return index; + } + + const Char* rt_alloc_string(const Char* src) + { + const Char* string = new Char[rt_string_len(src) + 1]; + + if (!string) + return nullptr; + + voidPtr v_src = reinterpret_cast<voidPtr>(const_cast<char*>(src)); + voidPtr v_dst = reinterpret_cast<voidPtr>(const_cast<char*>(string)); + + rt_copy_memory(v_src, v_dst, rt_string_len(src) + 1); + + return string; + } + + Int32 rt_to_uppercase(Int32 character) + { + if (character >= 'a' && character <= 'z') + return character - 0x20; + + return character; + } + + Int32 rt_is_alnum(Int32 character) + { + return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9'); + } + + Int32 rt_to_lower(Int32 character) + { + if (character >= 'A' && character <= 'Z') + return character + 0x20; + + return character; + } + + Boolean rt_is_space(Char chr) + { + return chr == ' '; + } + + Boolean rt_is_newln(Char chr) + { + return chr == '\n'; + } + + VoidPtr rt_string_in_string(const Char* in, const Char* needle) + { + for (SizeT i = 0; i < rt_string_len(in); ++i) + { + if (rt_string_cmp(in + i, needle, rt_string_len(needle)) == 0) + return reinterpret_cast<voidPtr>(const_cast<char*>(in + i)); + } + + return nullptr; + } + + Char rt_to_char(UInt64 base, Int32 limit) + { + const Char kNumbers[17] = "0123456789ABCDEF"; + return kNumbers[base % limit]; + } + + Bool rt_to_string(Char* str, UInt64 base, Int32 limit) + { +#ifdef __NE_AMD64__ + auto i = 0; + + auto final_number = base; + + auto mult = 1; + auto elems = 0L; + + base /= 10; + + while (base > 0) + { + elems++; + mult *= 10; + base /= 10; + } + + while (elems > -1) + { + final_number = (final_number % mult) * 10 + final_number / mult; + str[i] = rt_to_char(final_number, limit); + + --elems; + ++i; + } +#endif + + return YES; + } + + /// @brief Checks for a string start at the character. + + Char* rt_string_has_char(Char* str, const Char chr) + { + while (*str != chr) + { + ++str; + + if (*str == 0) + return nullptr; + } + + return str; + } +} // namespace NeOS + +EXTERN_C void* memset(void* dst, int c, long long unsigned int len) +{ + return NeOS::rt_set_memory(dst, c, len); +} + +EXTERN_C void* memcpy(void* dst, const void* src, long long unsigned int len) +{ + NeOS::rt_copy_memory(const_cast<void*>(src), dst, len); + return dst; +} diff --git a/dev/kernel/src/Variant.cc b/dev/kernel/src/Variant.cc new file mode 100644 index 00000000..cfa29d3a --- /dev/null +++ b/dev/kernel/src/Variant.cc @@ -0,0 +1,41 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <NewKit/Variant.h> + +namespace NeOS +{ + const Char* Variant::ToString() + { + switch (fKind) + { + case VariantKind::kXML: + return ("Class:{XML}"); + case VariantKind::kJson: + return ("Class:{Json}"); + case VariantKind::kString: + return ("Class:{String}"); + case VariantKind::kBlob: + return ("Class:{Blob}"); + case VariantKind::kNull: + return ("Class:{Null}"); + default: + return ("Class:{Unknown}"); + } + } + + /// @brief Return variant's kind. + Variant::VariantKind& Variant::Kind() + { + return this->fKind; + } + + /// @brief Leak variant's instance. + VoidPtr Variant::Leak() + { + return this->fPtr; + } +} // namespace NeOS |
