summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-11-15 09:29:09 +0100
committerAmlal El Mahrouss <amlal@nekernel.org>2025-11-15 09:31:37 +0100
commit9b429d2effec17dc4e2e7b2dee7a1fd950aa715e (patch)
treea67cf44c3b51e8f8d91490101ceb805b319adac8
parentb2c4d9a8ebebf87be33dcc357af86102d31dac47 (diff)
feat: kernel: New PE32+ backend, CodeMgr improvements.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
-rw-r--r--dev/kernel/FirmwareKit/EPM.h2
-rw-r--r--dev/kernel/KernelKit/PE32CodeMgr.h91
-rw-r--r--dev/kernel/src/PE32CodeMgr.cc258
-rw-r--r--dev/kernel/src/PEFCodeMgr.cc2
-rw-r--r--docs/tex/binary_mutex.tex6
-rw-r--r--docs/tex/core_process_scheduler.tex2
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}