diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2025-11-15 09:29:09 +0100 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal@nekernel.org> | 2025-11-15 09:31:37 +0100 |
| commit | 9b429d2effec17dc4e2e7b2dee7a1fd950aa715e (patch) | |
| tree | a67cf44c3b51e8f8d91490101ceb805b319adac8 | |
| parent | b2c4d9a8ebebf87be33dcc357af86102d31dac47 (diff) | |
feat: kernel: New PE32+ backend, CodeMgr improvements.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
| -rw-r--r-- | dev/kernel/FirmwareKit/EPM.h | 2 | ||||
| -rw-r--r-- | dev/kernel/KernelKit/PE32CodeMgr.h | 91 | ||||
| -rw-r--r-- | dev/kernel/src/PE32CodeMgr.cc | 258 | ||||
| -rw-r--r-- | dev/kernel/src/PEFCodeMgr.cc | 2 | ||||
| -rw-r--r-- | docs/tex/binary_mutex.tex | 6 | ||||
| -rw-r--r-- | docs/tex/core_process_scheduler.tex | 2 |
6 files changed, 355 insertions, 6 deletions
diff --git a/dev/kernel/FirmwareKit/EPM.h b/dev/kernel/FirmwareKit/EPM.h index 20c966e4..11776606 100644 --- a/dev/kernel/FirmwareKit/EPM.h +++ b/dev/kernel/FirmwareKit/EPM.h @@ -102,7 +102,7 @@ enum { kEPMLinux = 0x8f, /// @brief Linux on EPM. kEPMBSD = 0x9f, /// @brief BSD on EPM. kEPMNeKernel = 0x1f, /// @brief NeKernel. - kEPMVMKernel = 0x2f, /// @brief VMKernel. + kEPMLegacy = 0x2f, /// @brief Legacy VMKernel. /// @note ... the rest is reserved for future OSes. kEPMInvalidOS = 0xff, }; diff --git a/dev/kernel/KernelKit/PE32CodeMgr.h b/dev/kernel/KernelKit/PE32CodeMgr.h new file mode 100644 index 00000000..da9f0737 --- /dev/null +++ b/dev/kernel/KernelKit/PE32CodeMgr.h @@ -0,0 +1,91 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + + File: PE32CodeMgr.h + Purpose: PE32+ Code Mgr and Dylib mgr. + + Revision History: + + 12/02/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +//////////////////////////////////////////////////// + +// LAST REV: Mon Feb 12 13:52:01 CET 2024 + +//////////////////////////////////////////////////// + +#include <KernelKit/FileMgr.h> +#include <KernelKit/ILoader.h> +#include <KernelKit/PE.h> +#include <NeKit/ErrorOr.h> +#include <NeKit/KString.h> + +#ifndef INC_PROCESS_SCHEDULER_H +#include <KernelKit/ProcessScheduler.h> +#endif + +#define kPeStackSizeSymbol "__NESizeOfReserveStack" +#define kPeHeapSizeSymbol "__NESizeOfReserveHeap" +#define kPeNameSymbol "__NEProgramName" + +#define kPeApplicationMime "application/vnd-portable-executable" + +#define kPeImageStart "__ImageStart" + +namespace Kernel { +/// +/// \name PE32Loader +/// \brief PE32+ loader class. +/// +class PE32Loader : public ILoader { + private: + explicit PE32Loader() = delete; + + public: + explicit PE32Loader(const VoidPtr blob); + explicit PE32Loader(const Char* path); + ~PE32Loader() override; + + public: + NE_COPY_DEFAULT(PE32Loader) + + public: + const Char* Path() override; + const Char* AsString() override; + const Char* MIME() override; + + public: + ErrorOr<VoidPtr> FindStart() override; + ErrorOr<VoidPtr> FindSectionByName(const Char* name); + ErrorOr<VoidPtr> FindSymbol(const Char* name, Int32 kind) override; + ErrorOr<VoidPtr> GetBlob() override; + + public: + bool IsLoaded() noexcept; + + private: +#ifdef __FSKIT_INCLUDES_NEFS__ + OwnPtr<FileStream<Char, NeFileSystemMgr>> fFile; +#elif defined(__FSKIT_INCLUDES_HEFS__) + OwnPtr<FileStream<Char, HeFileSystemMgr>> fFile; +#else + OwnPtr<FileStream<Char>> fFile; +#endif // __FSKIT_INCLUDES_NEFS__ + + Ref<KString> fPath; + VoidPtr fCachedBlob; + BOOL fBad; +}; + +enum { kPEPlatformInvalid, kPEPlatformAMD64 = 100, kPEPlatformARM64 }; +enum { kPETypeInvalid, kPETypeText = 100, kPETypeData, kPETypeBSS }; + +typedef LDR_SECTION_HEADER PE_SECTION_INFO; + +ProcessID rtl_create_user_process(PE32Loader& exec, const Int32& process_kind) noexcept; +} // namespace NeKernel
\ No newline at end of file diff --git a/dev/kernel/src/PE32CodeMgr.cc b/dev/kernel/src/PE32CodeMgr.cc new file mode 100644 index 00000000..9b5b6b37 --- /dev/null +++ b/dev/kernel/src/PE32CodeMgr.cc @@ -0,0 +1,258 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include <CFKit/Utils.h> +#include <KernelKit/DebugOutput.h> +#include <KernelKit/HeapMgr.h> +#include <KernelKit/PE32CodeMgr.h> +#include <KernelKit/ProcessScheduler.h> +#include <NeKit/Defines.h> +#include <NeKit/KString.h> +#include <NeKit/OwnPtr.h> +#include <NeKit/KernelPanic.h> + +namespace Kernel { +namespace Detail { + /***********************************************************************************/ + /// @brief Get the PE32+ platform signature according to the compiled architecture. + /***********************************************************************************/ + + UInt32 ldr_get_platform_pe(void) noexcept { +#if defined(__NE_AMD64__) + return kPEPlatformAMD64; +#elif defined(__NE_ARM64__) + return kPEPlatformARM64; +#else + return kPEPlatformInvalid; +#endif // __32x0__ || __64x0__ || __x86_64__ + } +} // namespace Detail + +/***********************************************************************************/ +/// @brief PE32+ loader constructor w/ blob. +/// @param blob file blob. +/***********************************************************************************/ + +PE32Loader::PE32Loader(const VoidPtr blob) : fCachedBlob(blob) { + MUST_PASS(fCachedBlob); + fBad = false; +} + +/***********************************************************************************/ +/// @brief PE32+ loader constructor. +/// @param path the filesystem path. +/***********************************************************************************/ + +PE32Loader::PE32Loader(const Char* path) : fCachedBlob(nullptr), fBad(false) { + fFile.New(const_cast<Char*>(path), kRestrictRB); + fPath = KStringBuilder::Construct(path).Leak(); + + auto kPefHeader = "PE32_BLOB"; + fCachedBlob = fFile->Read(kPefHeader, 0); + + if (!fCachedBlob) fBad = YES; +} + +/***********************************************************************************/ +/// @brief PE32+ destructor. +/***********************************************************************************/ + +PE32Loader::~PE32Loader() { + if (fCachedBlob) mm_free_ptr(fCachedBlob); + + fFile.Delete(); +} + +/***********************************************************************************/ +/// @brief Finds the section according to its name. +/// @param name name of section. +/***********************************************************************************/ + +ErrorOr<VoidPtr> PE32Loader::FindSectionByName(const Char* name) { + if (!fCachedBlob || fBad || !name) return ErrorOr<VoidPtr>{kErrorInvalidData}; + + LDR_EXEC_HEADER_PTR header_ptr = CF::ldr_find_exec_header((const Char*) fCachedBlob); + LDR_OPTIONAL_HEADER_PTR opt_header_ptr = CF::ldr_find_opt_exec_header((const Char*) fCachedBlob); + + if (!header_ptr || !opt_header_ptr) return ErrorOr<VoidPtr>{kErrorInvalidData}; + +#ifdef __NE_AMD64__ + if (header_ptr->Machine != kPeMachineAMD64 || header_ptr->Signature != kPeSignature) { + return ErrorOr<VoidPtr>{kErrorInvalidData}; + } + +#elif defined(__NE_ARM64__) + if (header_ptr->Machine != kPeMachineARM64 || header_ptr->Signature != kPeSignature) { + return ErrorOr<VoidPtr>{kErrorInvalidData}; + } +#endif // __NE_AMD64__ || __NE_ARM64__ + + if (header_ptr->NumberOfSections < 1) { + return ErrorOr<VoidPtr>{kErrorInvalidData}; + } + + LDR_SECTION_HEADER_PTR secs = + (LDR_SECTION_HEADER_PTR) (((Char*) opt_header_ptr) + header_ptr->SizeOfOptionalHeader); + + for (SizeT sectIndex = 0; sectIndex < header_ptr->NumberOfSections; ++sectIndex) { + LDR_SECTION_HEADER_PTR sect = &secs[sectIndex]; + + if (KStringBuilder::Equals(name, sect->Name)) { + return ErrorOr<VoidPtr>(sect); + } + } + + return ErrorOr<VoidPtr>{kErrorInvalidData}; +} + +/***********************************************************************************/ +/// @brief Finds the symbol according to it's name. +/// @param name name of symbol. +/// @param kind kind of symbol we want. +/***********************************************************************************/ + +ErrorOr<VoidPtr> PE32Loader::FindSymbol(const Char* name, Int32 kind) { + if (!name || *name == 0) return ErrorOr<VoidPtr>{kErrorInvalidData}; + + auto section_name = "\0"; + + switch (kind) { + case kPETypeData: + section_name = ".data"; + break; + case kPETypeBSS: + section_name = ".bss"; + break; + case kPETypeText: + section_name = ".text"; + break; + default: + return ErrorOr<VoidPtr>{kErrorInvalidData}; + } + + auto sec = this->FindSectionByName(section_name); + LDR_SECTION_HEADER_PTR* sec_ptr = (LDR_SECTION_HEADER_PTR*) sec.Leak().Leak(); + + if (!sec_ptr || !*sec_ptr) return ErrorOr<VoidPtr>{kErrorInvalidData}; + + LDR_OPTIONAL_HEADER_PTR opt_header_ptr = CF::ldr_find_opt_exec_header((const Char*) fCachedBlob); + + if (opt_header_ptr) { + LDR_DATA_DIRECTORY_PTR data_dirs = + (LDR_DATA_DIRECTORY_PTR) ((UInt8*) opt_header_ptr + sizeof(LDR_OPTIONAL_HEADER)); + + LDR_DATA_DIRECTORY_PTR export_dir_entry = &data_dirs[0]; + + if (export_dir_entry->VirtualAddress == 0 || export_dir_entry->Size == 0) + return ErrorOr<VoidPtr>{kErrorInvalidData}; + + LDR_EXPORT_DIRECTORY* export_dir = + (LDR_EXPORT_DIRECTORY*) ((UIntPtr) fCachedBlob + export_dir_entry->VirtualAddress); + + UInt32* name_table = (UInt32*) ((UIntPtr) fCachedBlob + export_dir->AddressOfNames); + UInt16* ordinal_table = (UInt16*) ((UIntPtr) fCachedBlob + export_dir->AddressOfNameOrdinal); + UInt32* function_table = (UInt32*) ((UIntPtr) fCachedBlob + export_dir->AddressOfFunctions); + + for (UInt32 i = 0; i < export_dir->NumberOfNames; ++i) { + const char* exported_name = (const char*) ((UIntPtr) fCachedBlob + name_table[i]); + + if (KStringBuilder::Equals(exported_name, name)) { + UInt16 ordinal = ordinal_table[i]; + UInt32 rva = function_table[ordinal]; + + VoidPtr symbol_addr = (VoidPtr) ((UIntPtr) fCachedBlob + rva); + + return ErrorOr<VoidPtr>{symbol_addr}; + } + } + } + + return ErrorOr<VoidPtr>{kErrorInvalidData}; +} + +/// @brief Finds the executable entrypoint. +/// @return +ErrorOr<VoidPtr> PE32Loader::FindStart() { + if (auto sym = this->FindSymbol(kPeImageStart, 0); sym) return sym; + + return ErrorOr<VoidPtr>(kErrorExecutable); +} + +/// @brief Tells if the executable is loaded or not. +/// @return Whether it's not bad and is cached. +bool PE32Loader::IsLoaded() noexcept { + return !fBad && fCachedBlob; +} + +const Char* PE32Loader::Path() { + return fPath.Leak().CData(); +} + +const Char* PE32Loader::AsString() { +#ifdef __32x0__ + return "32x0 PE"; +#elif defined(__64x0__) + return "64x0 PE"; +#elif defined(__x86_64__) + return "x86_64 PE"; +#elif defined(__aarch64__) + return "AARCH64 PE"; +#elif defined(__powerpc64__) + return "POWER64 PE"; +#else + return "???? PE"; +#endif // __32x0__ || __64x0__ || __x86_64__ || __powerpc64__ +} + +const Char* PE32Loader::MIME() { + return kPeApplicationMime; +} + +ErrorOr<VoidPtr> PE32Loader::GetBlob() { + return ErrorOr<VoidPtr>{this->fCachedBlob}; +} + +namespace Utils { + ProcessID rtl_create_user_process(PE32Loader& exec, const Int32& process_kind) noexcept { + auto errOrStart = exec.FindStart(); + + if (errOrStart.Error() != kErrorSuccess) return kSchedInvalidPID; + + auto symname = exec.FindSymbol(kPeImageStart, 0); + + if (!symname) { + symname = ErrorOr<VoidPtr>{(VoidPtr) rt_alloc_string("UserProcess_PE32")}; + } + + auto id = + UserProcessScheduler::The().Spawn(reinterpret_cast<const Char*>(symname.Leak().Leak()), + errOrStart.Leak().Leak(), exec.GetBlob().Leak().Leak()); + + mm_free_ptr(symname.Leak().Leak()); + + if (id != kSchedInvalidPID) { + auto stacksym = exec.FindSymbol(kPeStackSizeSymbol, 0); + + if (!stacksym) { + stacksym = ErrorOr<VoidPtr>{(VoidPtr) new UIntPtr(kSchedMaxStackSz)}; + } + + if ((*(volatile UIntPtr*) stacksym.Leak().Leak()) > kSchedMaxStackSz) { + *(volatile UIntPtr*) stacksym.Leak().Leak() = kSchedMaxStackSz; + } + + UserProcessScheduler::The().TheCurrentTeam().AsArray()[id].Kind = process_kind; + UserProcessScheduler::The().TheCurrentTeam().AsArray()[id].StackSize = + *(UIntPtr*) stacksym.Leak().Leak(); + + mm_free_ptr(stacksym.Leak().Leak()); + stacksym.Leak().Leak() = nullptr; + } + + return id; + } +} // namespace Utils +} // namespace NeKernel
\ No newline at end of file diff --git a/dev/kernel/src/PEFCodeMgr.cc b/dev/kernel/src/PEFCodeMgr.cc index a0d0a6af..e8f71ac1 100644 --- a/dev/kernel/src/PEFCodeMgr.cc +++ b/dev/kernel/src/PEFCodeMgr.cc @@ -192,7 +192,7 @@ ErrorOr<VoidPtr> PEFLoader::FindSymbol(const Char* name, Int32 kind) { Char* unconst_symbol = const_cast<Char*>(name); for (SizeT i = 0UL; i < rt_string_len(unconst_symbol, kPefNameLen); ++i) { - if (unconst_symbol[i] == ' ') { + if (rt_is_space(unconst_symbol[i])) { unconst_symbol[i] = kMangleCharacter; } } diff --git a/docs/tex/binary_mutex.tex b/docs/tex/binary_mutex.tex index 1b5a59c2..0f6a6663 100644 --- a/docs/tex/binary_mutex.tex +++ b/docs/tex/binary_mutex.tex @@ -12,7 +12,7 @@ \section{Abstract} -{The BinaryMutex is a core component of NeKernel (NeKernel/VMKernel) based systems. The pattern excludes other acquirers to own the USER\_PROCESS that is currently being hold. Thus the acquiree is the USER\_PROCESS itself} +{The BinaryMutex is a core component of NeKernel (NeKernel/Legacy VMKernel) based systems. The pattern excludes other acquirers to own the USER\_PROCESS that is currently being hold. Thus the acquiree is the USER\_PROCESS itself} \section{Overview} @@ -64,13 +64,13 @@ class BinaryMutex final { \section{Conclusion} {This design pattern is useful for systems that need to make sure that a process isn't tampered by concurrent usages. -Thus its existence in VMKernel and NeKernel.} +Thus its existence in Legacy VMKernel and NeKernel.} \section{References} {NeKernel}: \href{https://github.com/nekernel-org/nekernel}{NeKernel} -{VMKernel}: \href{https://snu.systems/specs/vmkernel}{VMKernel} +{Legacy VMKernel}: \href{https://snu.systems/specs/vmkernel}{Legacy VMKernel} {BinaryMutex}: \href{https://github.com/nekernel-org/nekernel/blob/dev/dev/kernel/KernelKit/BinaryMutex.h}{BinaryMutex} diff --git a/docs/tex/core_process_scheduler.tex b/docs/tex/core_process_scheduler.tex index ab5636f6..41bad465 100644 --- a/docs/tex/core_process_scheduler.tex +++ b/docs/tex/core_process_scheduler.tex @@ -123,7 +123,7 @@ struct ProcessImage final { {NeKernel}: \href{https://github.com/nekernel-org/nekernel}{NeKernel} -{VMKernel}: \href{https://snu.systems/specs/vmkernel}{VMKernel} +{Legacy VMKernel}: \href{https://snu.systems/specs/vmkernel}{Legacy VMKernel} {CoreProcessScheduler C++ Header}: \href{https://github.com/nekernel-org/nekernel/blob/dev/dev/kernel/KernelKit/CoreProcessScheduler.h}{CoreProcessScheduler} |
