summaryrefslogtreecommitdiffhomepage
path: root/src/boot/BootKit/BootKit.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot/BootKit/BootKit.h')
-rw-r--r--src/boot/BootKit/BootKit.h335
1 files changed, 335 insertions, 0 deletions
diff --git a/src/boot/BootKit/BootKit.h b/src/boot/BootKit/BootKit.h
new file mode 100644
index 00000000..e1a2b628
--- /dev/null
+++ b/src/boot/BootKit/BootKit.h
@@ -0,0 +1,335 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+/***********************************************************************************/
+/// @file BootKit.h
+/// @brief Bootloader Application Programming Interface.
+/***********************************************************************************/
+
+#pragma once
+
+#include <BootKit/HW/ATA.h>
+#include <CompilerKit/Version.h>
+#include <modules/CoreGfx/CoreGfx.h>
+
+/// include NeFS header and Support header as well.
+
+#include <BootKit/Support.h>
+#include <FSKit/NeFS.h>
+
+/***********************************************************************************/
+/// Include other APIs.
+/***********************************************************************************/
+
+#include <NeKit/Defines.h>
+#include <modules/ATA/ATA.h>
+
+#include <FirmwareKit/EFI.h>
+#include <FirmwareKit/EPM.h>
+#include <FirmwareKit/GPT.h>
+#include <FirmwareKit/VEPM.h>
+
+#define kBKBootFileMime "boot-x/file"
+#define kBKBootDirMime "boot-x/dir"
+
+/***********************************************************************************/
+/// Framebuffer helpers.
+/***********************************************************************************/
+
+namespace Boot {
+void ThrowError(const WideChar* errorCode, const WideChar* reason) noexcept;
+
+class BootTextWriter;
+class BootFileReader;
+class BootThread;
+class BVersionString;
+
+typedef Char* PEFImagePtr;
+typedef Char* PEImagePtr;
+
+typedef WideChar CharacterTypeUTF16;
+typedef Char CharacterTypeASCII;
+typedef char8_t CharacterTypeUTF8;
+
+using namespace Kernel;
+
+/**
+ * @brief BootKit Text Writer class
+ * Writes to UEFI StdOut.
+ */
+class BootTextWriter final {
+ BootTextWriter& _Write(const UInt64& num);
+
+ public:
+ BootTextWriter& Write(const UInt64& num);
+ BootTextWriter& Write(const Char* str);
+ BootTextWriter& Write(const CharacterTypeUTF16* str);
+ BootTextWriter& WriteCharacter(CharacterTypeUTF16 c);
+ BootTextWriter& Write(const UChar* str);
+
+ template <typename T>
+ BootTextWriter& operator<<(T elem) {
+ this->Write(elem);
+ return *this;
+ }
+
+ public:
+ explicit BootTextWriter() = default;
+ ~BootTextWriter() = default;
+
+ public:
+ BootTextWriter& operator=(const BootTextWriter&) = default;
+ BootTextWriter(const BootTextWriter&) = default;
+};
+
+Kernel::SizeT BCopyMem(CharacterTypeUTF16* dest, CharacterTypeUTF16* src, const Kernel::SizeT len);
+
+Kernel::SizeT BSetMem(CharacterTypeASCII* src, const CharacterTypeASCII byte,
+ const Kernel::SizeT len);
+
+/// String length functions.
+
+/// @brief get string length.
+Kernel::SizeT BStrLen(const CharacterTypeUTF16* ptr);
+
+/// @brief set memory with custom value.
+Kernel::SizeT BSetMem(CharacterTypeUTF16* src, const CharacterTypeUTF16 byte,
+ const Kernel::SizeT len);
+
+/**
+ * @brief BootKit File Reader class
+ * Reads the Firmware Boot partition and filesystem.
+ */
+class BootFileReader final {
+ public:
+ explicit BootFileReader(const CharacterTypeUTF16* path, EfiHandlePtr ImageHandle);
+ ~BootFileReader();
+
+ public:
+ Void ReadAll(SizeT until, SizeT chunk = kib_cast(4), UIntPtr out_address = 0UL);
+
+ enum {
+ kOperationOkay,
+ kNotSupported,
+ kEmptyDirectory,
+ kNoSuchEntry,
+ kIsDirectory,
+ kTooSmall,
+ kCount,
+ };
+
+ /// @brief error code getter.
+ /// @return the error code.
+ Int32& Error();
+
+ /// @brief blob getter.
+ /// @return the blob.
+ VoidPtr Blob();
+
+ /// @breif Size getter.
+ /// @return the size of the file.
+ UInt64& Size();
+
+ public:
+ BootFileReader& operator=(const BootFileReader&) = default;
+ BootFileReader(const BootFileReader&) = default;
+
+ private:
+ Int32 mErrorCode{kOperationOkay};
+ VoidPtr mBlob{nullptr};
+ CharacterTypeUTF16 mPath[kPathLen];
+ BootTextWriter mWriter;
+ EfiFileProtocol* mFile{nullptr};
+ UInt64 mSizeFile{0};
+ EfiFileProtocol* mRootFs;
+};
+
+typedef UInt8* BlobType;
+
+/// @brief Bootloader Version String.
+class BVersionString final {
+ public:
+ static const CharacterTypeASCII* The() { return BOOTLOADER_VERSION; }
+};
+
+/***********************************************************************************/
+/// Provide some useful processor features.
+/***********************************************************************************/
+
+#ifdef __EFI_x86_64__
+
+/***
+ * Common processor instructions.
+ */
+
+EXTERN_C void rt_out8(UInt16 port, UInt8 value);
+EXTERN_C void rt_out16(UInt16 port, UInt16 value);
+EXTERN_C void rt_out32(UInt16 port, UInt32 value);
+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_halt();
+EXTERN_C void rt_cli();
+EXTERN_C void rt_sti();
+EXTERN_C void rt_cld();
+EXTERN_C void rt_std();
+
+#endif // __EFI_x86_64__
+
+/// @brief BootKit Drive Formatter.
+template <typename BootDev>
+class BDiskFormatFactory final {
+ public:
+ /// @brief File entry for **BDiskFormatFactory**.
+ struct BFileDescriptor final {
+ Char fFileName[kNeFSCatalogNameLen];
+ Int32 fKind;
+ };
+
+ public:
+ explicit BDiskFormatFactory() = default;
+ ~BDiskFormatFactory() = default;
+
+ NE_COPY_DELETE(BDiskFormatFactory)
+
+ /// @brief Format disk using partition name and blob.
+ /// @param Partition part_name the target partition name.
+ /// @param blob blobs array.
+ /// @param blob_sz blobs array count.
+ /// @retval True disk has been formatted.
+ /// @retval False failed to format.
+ Boolean Format(const Char* part_name);
+
+ /// @brief check if partition is good.
+ Bool IsPartitionValid() noexcept {
+#if defined(BOOTZ_EPM_SUPPORT)
+ fDiskDev.Leak().mBase = (kEPMBootBlockLba);
+ fDiskDev.Leak().mSize = sizeof(EPM_PART_BLOCK);
+
+ EPM_PART_BLOCK buf_epm = {};
+
+ fDiskDev.Read((Char*) &buf_epm, sizeof(EPM_PART_BLOCK));
+
+ if (StrCmp(buf_epm.Magic, kEPMMagic) > 0) {
+ return false;
+ }
+
+ if (buf_epm.Version != kEPMRevisionBcd) {
+ return false;
+ }
+
+ BootTextWriter writer;
+ writer.Write("BootZ: EPM Partition found.\r");
+
+ return true;
+#else
+ GPT_PARTITION_TABLE* gpt_part = (GPT_PARTITION_TABLE*) RTL_ALLOCA(sizeof(GPT_PARTITION_TABLE));
+
+ fDiskDev.Leak().mBase = (kGPTPartitionTableLBA);
+ fDiskDev.Leak().mSize = sizeof(GPT_PARTITION_TABLE);
+
+ fDiskDev.Read((Char*) gpt_part, sizeof(GPT_PARTITION_TABLE));
+
+ BootTextWriter writer;
+
+ if (StrCmp(gpt_part->Signature, kMagicGPT) == 0) {
+ writer.Write("BootZ: GPT Partition found.\r");
+ return true;
+ }
+
+ writer.Write("BootZ: No Partition found.\r");
+
+ return false;
+#endif
+ }
+
+ private:
+ BootDev fDiskDev;
+};
+
+/// @brief Format disk with a specific partition scheme.
+/// @param part_name partition Name
+/// @retval True disk has been formatted.
+/// @retval False failed to format.
+template <typename BootDev>
+inline Boolean BDiskFormatFactory<BootDev>::Format(const Char* part_name) {
+#if defined(BOOTZ_EPM_SUPPORT)
+ EPM_PART_BLOCK* epm_boot = (EPM_PART_BLOCK*) RTL_ALLOCA(sizeof(EPM_PART_BLOCK));
+
+ const auto kFsName = "NeKernel";
+ const auto kBlockName = " NeKernelOS";
+
+ epm_boot->FsVersion = 0;
+ epm_boot->LbaStart = sizeof(EPM_PART_BLOCK);
+ epm_boot->LbaEnd = fDiskDev.GetDiskSize() - 1;
+ epm_boot->SectorSz = BootDev::kSectorSize;
+ epm_boot->Kind = kEPMNeKernel;
+ epm_boot->NumBlocks = 1;
+
+ epm_boot->Guid = kEPMNilGuid;
+
+ CopyMem(epm_boot->Fs, reinterpret_cast<VoidPtr>(const_cast<Char*>(kFsName)), StrLen(kFsName));
+ CopyMem(epm_boot->Name, reinterpret_cast<VoidPtr>(const_cast<Char*>(kBlockName)),
+ StrLen(kBlockName));
+ CopyMem(epm_boot->Magic, reinterpret_cast<VoidPtr>(const_cast<Char*>(kEPMMagic)),
+ StrLen(kEPMMagic));
+
+ fDiskDev.Leak().mBase = kEPMBootBlockLba; // always always resies at zero block.
+ fDiskDev.Leak().mSize = sizeof(EPM_PART_BLOCK);
+
+ fDiskDev.Write((Char*) epm_boot, sizeof(EPM_PART_BLOCK));
+
+ BootTextWriter writer;
+ writer.Write(L"BootZ: Drive is EPM formatted.\r");
+#elif defined(BOOTZ_GPT_SUPPORT)
+ NE_UNUSED(part_name);
+
+ GPT_PARTITION_TABLE* gpt_part = (GPT_PARTITION_TABLE*) RTL_ALLOCA(sizeof(GPT_PARTITION_TABLE));
+
+ CopyMem(gpt_part->Signature, reinterpret_cast<VoidPtr>(const_cast<Char*>(kMagicGPT)),
+ StrLen(kMagicGPT));
+
+ gpt_part->Revision = 0x00010000;
+ gpt_part->HeaderSize = sizeof(GPT_PARTITION_TABLE);
+
+ gpt_part->CRC32 = 0x00000000;
+
+ gpt_part->Reserved1 = 0x00000000;
+ gpt_part->LBAHeader = 0x00000000;
+ gpt_part->LBAAltHeader = 0x00000000;
+ gpt_part->FirstGPTEntry = 0x00000000;
+ gpt_part->LastGPTEntry = 0x00000000;
+
+ gpt_part->Guid.Data1 = 0x00000000;
+ gpt_part->Guid.Data2 = 0x0000;
+ gpt_part->Guid.Data3 = 0x0000;
+
+ SetMem(gpt_part->Guid.Data4, 0, 8);
+
+ gpt_part->Revision = 0x00010000;
+
+ gpt_part->StartingLBA = 0x00000000;
+ gpt_part->NumPartitionEntries = 0x00000000;
+ gpt_part->SizeOfEntries = 0x00000000;
+ gpt_part->CRC32PartEntry = 0x00000000;
+
+ SetMem(gpt_part->Reserved2, 0, kSectorAlignGPT_PartTbl);
+
+ fDiskDev.Leak().mBase = kGPTPartitionTableLBA; // always always resies at zero block.
+ fDiskDev.Leak().mSize = sizeof(GPT_PARTITION_TABLE);
+
+ fDiskDev.Write((Char*) gpt_part, sizeof(GPT_PARTITION_TABLE));
+
+ BootTextWriter writer;
+ writer.Write(L"BootZ: Drive is GPT formatted.\r");
+#else
+ NE_UNUSED(part_name);
+#endif
+
+ return YES;
+}
+} // namespace Boot