diff --git a/Core/Disk.cpp b/Core/Disk.cpp new file mode 100644 index 00000000..a038a540 --- /dev/null +++ b/Core/Disk.cpp @@ -0,0 +1,155 @@ +#include + +#include +#include + +#include "../kernel.h" +#include "../DAPI.hpp" +#include "../Fex.hpp" + +namespace Disk +{ + void Manager::FetchDisks(unsigned long DriverUID) + { + KernelCallback *callback = (KernelCallback *)KernelAllocator.RequestPages(TO_PAGES(sizeof(KernelCallback))); + memset(callback, 0, sizeof(KernelCallback)); + callback->Reason = FetchReason; + DriverManager->IOCB(DriverUID, (void *)callback); + this->AvailablePorts = callback->DiskCallback.Fetch.Ports; + this->BytesPerSector = callback->DiskCallback.Fetch.BytesPerSector; + + if (this->AvailablePorts <= 0) + { + KernelAllocator.FreePages((void *)callback, TO_PAGES(sizeof(KernelCallback))); + return; + } + + uint8_t *RWBuffer = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(this->BytesPerSector)); + + for (unsigned char ItrPort = 0; ItrPort < this->AvailablePorts; ItrPort++) + { + Drive *drive = new Drive; + sprintf_(drive->Name, "sd%ld-%d", DriverUID, this->AvailablePorts); + // TODO: Implement disk type detection. Very useful in the future. + drive->MechanicalDisk = true; + + memset(RWBuffer, 0, this->BytesPerSector); + memset(callback, 0, sizeof(KernelCallback)); + callback->Reason = ReceiveReason; + callback->DiskCallback.RW = { + .Sector = 0, + .SectorCount = 2, + .Port = ItrPort, + .Buffer = RWBuffer, + .Write = false, + }; + DriverManager->IOCB(DriverUID, (void *)callback); + memcpy(&drive->Table, RWBuffer, sizeof(PartitionTable)); + + /* + ----> Add to devfs the disk + */ + + if (drive->Table.GPT.Signature == GPT_MAGIC) + { + drive->Style = GPT; + uint32_t Entries = 512 / drive->Table.GPT.EntrySize; + uint32_t Sectors = drive->Table.GPT.PartCount / Entries; + for (uint32_t Block = 0; Block < Sectors; Block++) + { + memset(RWBuffer, 0, this->BytesPerSector); + memset(callback, 0, sizeof(KernelCallback)); + callback->Reason = ReceiveReason; + callback->DiskCallback.RW = { + .Sector = 2 + Block, + .SectorCount = 1, + .Port = ItrPort, + .Buffer = RWBuffer, + .Write = false, + }; + DriverManager->IOCB(DriverUID, (void *)callback); + + for (uint32_t e = 0; e < Entries; e++) + { + GUIDPartitionTablePartition GPTPartition = reinterpret_cast(RWBuffer)[e]; + if (GPTPartition.TypeLow || GPTPartition.TypeHigh) + { + Partition *partition = new Partition; + memcpy(partition->Label, GPTPartition.Label, sizeof(partition->Label)); + partition->StartLBA = GPTPartition.StartLBA; + partition->EndLBA = GPTPartition.EndLBA; + partition->Sectors = partition->EndLBA - partition->StartLBA; + partition->Port = ItrPort; + partition->Flags = Present; + partition->Style = GPT; + if (GPTPartition.Attributes & 1) + partition->Flags |= EFISystemPartition; + partition->Index = drive->Partitions.size(); + // why there is NUL (\0) between every char????? + char PartName[72]; + memcpy(PartName, GPTPartition.Label, 72); + for (char i = 0; i < 72; i++) + if (PartName[i] == '\0') + PartName[i] = ' '; + PartName[71] = '\0'; + trace("GPT partition \"%s\" found with %lld sectors", PartName, partition->Sectors); + drive->Partitions.push_back(partition); + + char *PartitionName = new char[64]; + sprintf_(PartitionName, "sd%ldp%ld", drives.size() - 1, partition->Index); + + /* + ----> Add to devfs the disk + */ + + delete[] PartitionName; + } + } + } + trace("%d GPT partitions found.", drive->Partitions.size()); + } + else if (drive->Table.MBR.Signature[0] == MBR_MAGIC0 && drive->Table.MBR.Signature[1] == MBR_MAGIC1) + { + drive->Style = MBR; + for (size_t p = 0; p < 4; p++) + if (drive->Table.MBR.Partitions[p].LBAFirst != 0) + { + Partition *partition = new Partition; + partition->StartLBA = drive->Table.MBR.Partitions[p].LBAFirst; + partition->EndLBA = drive->Table.MBR.Partitions[p].LBAFirst + drive->Table.MBR.Partitions[p].Sectors; + partition->Sectors = drive->Table.MBR.Partitions[p].Sectors; + partition->Port = ItrPort; + partition->Flags = Present; + partition->Style = MBR; + partition->Index = drive->Partitions.size(); + trace("Partition \"%#llx\" found with %lld sectors.", drive->Table.MBR.UniqueID, partition->Sectors); + drive->Partitions.push_back(partition); + + char *PartitionName = new char[64]; + sprintf_(PartitionName, "sd%ldp%ld", drives.size() - 1, partition->Index); + + /* + ----> Add to devfs the disk + */ + + delete[] PartitionName; + } + trace("%d MBR partitions found.", drive->Partitions.size()); + } + else + warn("No partition table found on port %d!", ItrPort); + + drives.push_back(drive); + } + + KernelAllocator.FreePages((void *)callback, TO_PAGES(sizeof(KernelCallback))); + } + + Manager::Manager() + { + } + + Manager::~Manager() + { + } +} diff --git a/KThread.cpp b/KThread.cpp index 6ee60404..b9d0dc4a 100644 --- a/KThread.cpp +++ b/KThread.cpp @@ -6,13 +6,19 @@ #include #include +#include "DAPI.hpp" +#include "Fex.hpp" + Driver::Driver *DriverManager = nullptr; +Disk::Manager *DiskManager = nullptr; void StartFilesystem() { KPrint("Initializing Filesystem..."); vfs = new FileSystem::Virtual; new FileSystem::USTAR((uint64_t)bInfo->Modules[0].Address, vfs); // TODO: Detect initrd + KPrint("Initializing Disk Manager..."); + DiskManager = new Disk::Manager; /* ... */ TEXIT(0); } @@ -24,6 +30,19 @@ void LoadDrivers() TEXIT(0); } +void FetchDisks() +{ + KPrint("Fetching Disks..."); + foreach (auto Driver in DriverManager->GetDrivers()) + { + FexExtended *DrvExtHdr = (FexExtended *)((uint64_t)Driver->Address + EXTENDED_SECTION_ADDRESS); + + if (DrvExtHdr->Driver.Type == FexDriverType::FexDriverType_Storage) + DiskManager->FetchDisks(Driver->DriverUID); + } + TEXIT(0); +} + void KernelMainThread() { Tasking::TCB *CurrentWorker = nullptr; @@ -31,7 +50,7 @@ void KernelMainThread() KPrint("C++ Language Version (__cplusplus) :%ld", __cplusplus); CurrentWorker = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)StartFilesystem); - CurrentWorker->Rename("Filesystem"); + CurrentWorker->Rename("Disk"); CurrentWorker->SetPriority(100); TaskManager->WaitForThread(CurrentWorker); @@ -39,6 +58,12 @@ void KernelMainThread() CurrentWorker->Rename("Drivers"); CurrentWorker->SetPriority(100); TaskManager->WaitForThread(CurrentWorker); + + CurrentWorker = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)FetchDisks); + CurrentWorker->Rename("Fetch Disks"); + CurrentWorker->SetPriority(100); + TaskManager->WaitForThread(CurrentWorker); + KPrint("Waiting for userspace process to start..."); /* Load init file */ CPU::Halt(true); diff --git a/include/disk.hpp b/include/disk.hpp new file mode 100644 index 00000000..0419eb84 --- /dev/null +++ b/include/disk.hpp @@ -0,0 +1,137 @@ +#ifndef __FENNIX_KERNEL_DISK_H__ +#define __FENNIX_KERNEL_DISK_H__ + +#include +#include + +namespace Disk +{ +#define MBR_MAGIC0 0x55 +#define MBR_MAGIC1 0xAA + +// "EFI PART" +#define GPT_MAGIC 0x5452415020494645ULL + + enum PartitionStyle + { + Unknown, + MBR, + GPT + }; + + enum PartitionFlags + { + Present, + Bootable, + EFISystemPartition + }; + + struct MasterBootRecordPartition + { + uint8_t Flags; + uint8_t CHSFirst[3]; + uint8_t Type; + uint8_t CHSLast[3]; + uint32_t LBAFirst; + uint32_t Sectors; + } __attribute__((packed)); + + struct MasterBootRecord + { + uint8_t Bootstrap[440]; + uint32_t UniqueID; + uint16_t Reserved; + MasterBootRecordPartition Partitions[4]; + uint8_t Signature[2]; + } __attribute__((packed)); + + struct GUIDPartitionTablePartition + { + uint64_t TypeLow; + uint64_t TypeHigh; + uint64_t GUIDLow; + uint64_t GUIDHigh; + uint64_t StartLBA; + uint64_t EndLBA; + uint64_t Attributes; + char Label[72]; + } __attribute__((packed)); + + struct GUIDPartitionTable + { + uint64_t Signature; + uint32_t Revision; + uint32_t HdrSize; + uint32_t HdrCRC32; + uint32_t Reserved; + uint64_t LBA; + uint64_t ALTLBA; + uint64_t FirstBlock; + uint64_t LastBlock; + uint64_t GUIDLow; + uint64_t GUIDHigh; + uint64_t PartLBA; + uint32_t PartCount; + uint32_t EntrySize; + uint32_t PartCRC32; + } __attribute__((packed)); + + struct PartitionTable + { + MasterBootRecord MBR; + GUIDPartitionTable GPT; + }; + + class Partition + { + public: + char Label[72] = "Unidentified Partition"; + uint64_t StartLBA = 0xdeadbeef; + uint64_t EndLBA = 0xdeadbeef; + uint64_t Sectors = 0xdeadbeef; + uint64_t Flags = 0xdeadbeef; + unsigned char Port = 0xdeadbeef; + PartitionStyle Style = PartitionStyle::Unknown; + size_t Index = 0; + + uint64_t Read(uint64_t Offset, uint64_t Count, uint8_t *Buffer) {} + uint64_t Write(uint64_t Offset, uint64_t Count, uint8_t *Buffer) {} + Partition() {} + ~Partition() {} + }; + + class Drive + { + public: + char Name[64] = "Unidentified Drive"; + uint8_t *Buffer = nullptr; + PartitionTable Table; + PartitionStyle Style = PartitionStyle::Unknown; + Vector Partitions; + bool MechanicalDisk = false; + uint64_t UniqueIdentifier = 0xdeadbeef; + + uint64_t Read(uint64_t Offset, uint64_t Count, uint8_t *Buffer) {} + uint64_t Write(uint64_t Offset, uint64_t Count, uint8_t *Buffer) {} + Drive() + { // TODO: Allocate buffer + } + ~Drive() {} + }; + + class Manager + { + private: + unsigned char AvailablePorts = 0; + int BytesPerSector = 0; + + Vector drives; + + public: + void FetchDisks(unsigned long DriverUID); + Manager(); + ~Manager(); + }; +} + +#endif // !__FENNIX_KERNEL_DISK_H__ diff --git a/kernel.h b/kernel.h index 5e9bc717..20693695 100644 --- a/kernel.h +++ b/kernel.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #endif @@ -27,6 +28,7 @@ extern Tasking::Task *TaskManager; extern Time::time *TimeManager; extern FileSystem::Virtual *vfs; extern Driver::Driver *DriverManager; +extern Disk::Manager *DiskManager; #define PEXIT(Code) TaskManager->GetCurrentProcess()->ExitCode = Code #define TEXIT(Code) TaskManager->GetCurrentThread()->ExitCode = Code