diff --git a/Core/Driver.cpp b/Core/Driver.cpp new file mode 100644 index 00000000..2373c1ea --- /dev/null +++ b/Core/Driver.cpp @@ -0,0 +1,266 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "../kernel.h" +#include "../DAPI.hpp" +#include "../Fex.hpp" + +NewLock(DriverDisplayPrintLock); + +namespace Driver +{ + const char *DriverTypesName[] = { + "Unknown", + "Generic", + "Display", + "Network", + "Storage", + "FileSystem", + "Input", + "Audio"}; + + void DriverDebugPrint(char *String, unsigned long DriverUID) + { + SmartLock(DriverDisplayPrintLock); + trace("[%ld] %s", DriverUID, String); + } + + void DriverDisplayPrint(char *String) + { + SmartLock(DriverDisplayPrintLock); + for (unsigned long i = 0; i < strlen(String); i++) + Display->Print(String[i], 0, true); + } + + void *RequestPage(unsigned long Size) + { + SmartLock(DriverDisplayPrintLock); + return KernelAllocator.RequestPages(Size); + } + + void FreePage(void *Page, unsigned long Size) + { + SmartLock(DriverDisplayPrintLock); + KernelAllocator.FreePages(Page, Size); + } + + void *Drivermemcpy(void *Destination, void *Source, unsigned long Size) + { + SmartLock(DriverDisplayPrintLock); + return memcpy(Destination, Source, Size); + } + + KernelAPI KAPI = { + .Version = { + .Major = 0, + .Minor = 0, + .Patch = 1}, + .Info = { + .Offset = 0, + .DriverUID = 0, + }, + .Memory = { + .PageSize = PAGE_SIZE, + .RequestPage = RequestPage, + .FreePage = FreePage, + }, + .PCI = { + .GetDeviceName = nullptr, + .Write = nullptr, + }, + .Util = { + .DebugPrint = DriverDebugPrint, + .DisplayPrint = DriverDisplayPrint, + .memcpy = Drivermemcpy, + }, + .Commmand = { + .Network = { + .SendPacket = nullptr, + .ReceivePacket = nullptr, + }, + }, + }; + + DriverCode Driver::CallDriverEntryPoint(void *fex) + { + KernelAPI *API = (KernelAPI *)KernelAllocator.RequestPages(TO_PAGES(sizeof(KernelAPI))); + memcpy(API, &KAPI, sizeof(KernelAPI)); + + API->Info.Offset = (unsigned long)fex; + API->Info.DriverUID = DriverUIDs++; + + int ret = ((int (*)(KernelAPI *))((uint64_t)((Fex *)fex)->Pointer + (uint64_t)fex))(API); + + if (DriverReturnCode::OK != ret) + return DriverCode::DRIVER_RETURNED_ERROR; + return DriverCode::OK; + } + + DriverCode Driver::LoadDriver(uint64_t DriverAddress, uint64_t Size) + { + Fex *DrvHdr = (Fex *)DriverAddress; + if (DrvHdr->Magic[0] != 'F' || DrvHdr->Magic[1] != 'E' || DrvHdr->Magic[2] != 'X' || DrvHdr->Magic[3] != '\0') + return DriverCode::INVALID_FEX_HEADER; + debug("Fex Magic: \"%s\"; Type: %d; OS: %d; Pointer: %#lx", DrvHdr->Magic, DrvHdr->Type, DrvHdr->OS, DrvHdr->Pointer); + + if (DrvHdr->Type == FexFormatType::FexFormatType_Driver) + { + FexExtended *DrvExtHdr = (FexExtended *)((uint64_t)DrvHdr + EXTENDED_SECTION_ADDRESS); + debug("Name: \"%s\"; Type: %d; Callback: %#lx", DrvExtHdr->Driver.Name, DrvExtHdr->Driver.Type, DrvExtHdr->Driver.Callback); + if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PCI) + { + Vector devices = PCIManager->FindPCIDevice(DrvExtHdr->Driver.Bind.PCI.VendorID, DrvExtHdr->Driver.Bind.PCI.DeviceID); + foreach (auto PCIDevice in devices) + { + Fex *fex = (Fex *)KernelAllocator.RequestPages(TO_PAGES(Size)); + memcpy(fex, (void *)DriverAddress, Size); + FexExtended *fexExtended = (FexExtended *)((uint64_t)fex + EXTENDED_SECTION_ADDRESS); + if (CallDriverEntryPoint(fex) != DriverCode::OK) + { + KernelAllocator.FreePages(fex, TO_PAGES(Size)); + return DriverCode::DRIVER_RETURNED_ERROR; + } + debug("Starting driver %s", fexExtended->Driver.Name); + + KernelCallback *KCallback = (KernelCallback *)KernelAllocator.RequestPages(TO_PAGES(sizeof(KernelCallback))); + + switch (fexExtended->Driver.Type) + { + case FexDriverType::FexDriverType_Generic: + { + fixme("Generic driver: %s", fexExtended->Driver.Name); + break; + } + case FexDriverType::FexDriverType_Display: + { + fixme("Display driver: %s", fexExtended->Driver.Name); + break; + } + case FexDriverType::FexDriverType_Network: + { + DriverInterruptHook *InterruptHook = new DriverInterruptHook(((int)((PCI::PCIHeader0 *)devices[0])->InterruptLine) + 32, // x86 + (void *)((uint64_t)fexExtended->Driver.Callback + (uint64_t)fex), + KCallback); + + KCallback->RawPtr = PCIDevice; + KCallback->Reason = CallbackReason::ConfigurationReason; + int callbackret = ((int (*)(KernelCallback *))((uint64_t)fexExtended->Driver.Callback + (uint64_t)fex))(KCallback); + if (callbackret == DriverReturnCode::NOT_IMPLEMENTED) + { + KernelAllocator.FreePages(fex, TO_PAGES(Size)); + KernelAllocator.FreePages(KCallback, TO_PAGES(sizeof(KernelCallback))); + error("Driver %s does not implement the configuration callback", fexExtended->Driver.Name); + continue; + } + else if (callbackret == DriverReturnCode::OK) + trace("Device found for driver: %s", fexExtended->Driver.Name); + else + { + KernelAllocator.FreePages(fex, TO_PAGES(Size)); + KernelAllocator.FreePages(KCallback, TO_PAGES(sizeof(KernelCallback))); + error("Driver %s returned error %d", fexExtended->Driver.Name, callbackret); + continue; + } + + memset(KCallback, 0, sizeof(KernelCallback)); + KCallback->Reason = CallbackReason::InterruptReason; + + DriverFile *drvfile = new DriverFile; + drvfile->DriverUID = KAPI.Info.DriverUID; + drvfile->Address = (void *)fex; + drvfile->InterruptHook = InterruptHook; + Drivers.push_back(drvfile); + break; + } + case FexDriverType::FexDriverType_Storage: + { + fixme("Storage driver: %s", fexExtended->Driver.Name); + break; + } + case FexDriverType::FexDriverType_FileSystem: + { + fixme("Filesystem driver: %s", fexExtended->Driver.Name); + break; + } + case FexDriverType::FexDriverType_Input: + { + fixme("Input driver: %s", fexExtended->Driver.Name); + break; + } + case FexDriverType::FexDriverType_Audio: + { + fixme("Audio driver: %s", fexExtended->Driver.Name); + break; + } + default: + { + warn("Unknown driver type: %d", fexExtended->Driver.Type); + break; + } + } + } + } + else + { + fixme("Driver bind type: %d", DrvExtHdr->Driver.Bind.Type); + } + } + else + return DriverCode::NOT_DRIVER; + return DriverCode::OK; + } + + Driver::Driver() + { + FileSystem::FILE *DriverDirectory = vfs->Open("/system/drivers"); + if (DriverDirectory->Status == FileSystem::FileStatus::OK) + foreach (auto driver in DriverDirectory->Node->Children) + if (driver->Flags == FileSystem::NodeFlags::FS_FILE) + if (cwk_path_has_extension(driver->Name)) + { + const char *extension; + cwk_path_get_extension(driver->Name, &extension, nullptr); + if (!strcmp(extension, ".fex")) + { + uint64_t ret = this->LoadDriver(driver->Address, driver->Length); + char retstring[64]; + if (ret == DriverCode::OK) + strcpy(retstring, "\e058C19OK"); + else + sprintf_(retstring, "\eE85230FAILED (%#lx)", ret); + KPrint("%s %s", driver->Name, retstring); + } + } + vfs->Close(DriverDirectory); + } + + Driver::~Driver() + { + } + +#if defined(__amd64__) + void DriverInterruptHook::OnInterruptReceived(CPU::x64::TrapFrame *Frame) +#elif defined(__i386__) + void DriverInterruptHook::OnInterruptReceived(void *Frame) +#elif defined(__aarch64__) + void DriverInterruptHook::OnInterruptReceived(void *Frame) +#endif + { + ((int (*)(void *))(Handle))(Data); + } + + DriverInterruptHook::DriverInterruptHook(int Interrupt, void *Address, void *ParamData) : Interrupts::Handler(Interrupt) + { + trace("Interrupt %d Hooked", Interrupt - 32); // x86 + Handle = Address; + Data = ParamData; + } + + DriverInterruptHook::~DriverInterruptHook() {} +} diff --git a/KThread.cpp b/KThread.cpp index 8bab788f..6ee60404 100644 --- a/KThread.cpp +++ b/KThread.cpp @@ -4,37 +4,49 @@ #include #include #include +#include + +Driver::Driver *DriverManager = nullptr; void StartFilesystem() { KPrint("Initializing Filesystem..."); - TaskManager->GetCurrentThread()->SetPriority(100); vfs = new FileSystem::Virtual; new FileSystem::USTAR((uint64_t)bInfo->Modules[0].Address, vfs); // TODO: Detect initrd - TaskManager->GetCurrentThread()->SetPriority(1); - debug("Filesystem service idling..."); - CPU::Halt(true); + /* ... */ + TEXIT(0); +} + +void LoadDrivers() +{ + KPrint("Loading Drivers..."); + DriverManager = new Driver::Driver; + TEXIT(0); } void KernelMainThread() { - KPrint("Kernel main thread started!"); - + Tasking::TCB *CurrentWorker = nullptr; KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD); KPrint("C++ Language Version (__cplusplus) :%ld", __cplusplus); - CPU::Interrupts(CPU::Disable); + CurrentWorker = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)StartFilesystem); + CurrentWorker->Rename("Filesystem"); + CurrentWorker->SetPriority(100); + TaskManager->WaitForThread(CurrentWorker); - TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)StartFilesystem)->Rename("Filesystem Service"); - - CPU::Interrupts(CPU::Enable); - TaskManager->GetCurrentThread()->SetPriority(1); + CurrentWorker = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)LoadDrivers); + CurrentWorker->Rename("Drivers"); + CurrentWorker->SetPriority(100); + TaskManager->WaitForThread(CurrentWorker); + KPrint("Waiting for userspace process to start..."); + /* Load init file */ CPU::Halt(true); } void KernelShutdownThread(bool Reboot) { - KPrint("Kernel shutdown thread started!"); + debug("Shutting down..."); if (Reboot) PowerManager->Reboot(); else diff --git a/include/driver.hpp b/include/driver.hpp new file mode 100644 index 00000000..75c18563 --- /dev/null +++ b/include/driver.hpp @@ -0,0 +1,67 @@ +#ifndef __FENNIX_KERNEL_DRIVER_H__ +#define __FENNIX_KERNEL_DRIVER_H__ + +#include + +#include +#include +#include +#include + +namespace Driver +{ + enum DriverCode + { + ERROR, + OK, + INVALID_FEX_HEADER, + INVALID_DRIVER_DATA, + NOT_DRIVER, + DRIVER_RETURNED_ERROR, + UNKNOWN_DRIVER_TYPE, + PCI_DEVICE_NOT_FOUND + }; + + class DriverInterruptHook : public Interrupts::Handler + { + private: + void *Handle; + void *Data; + +#if defined(__amd64__) + void OnInterruptReceived(CPU::x64::TrapFrame *Frame); +#elif defined(__i386__) + void OnInterruptReceived(void *Frame); +#elif defined(__aarch64__) + void OnInterruptReceived(void *Frame); +#endif + + public: + DriverInterruptHook(int Interrupt, void *Address, void *ParamData); + ~DriverInterruptHook(); + }; + + struct DriverFile + { + unsigned long DriverUID; + void *Address; + DriverInterruptHook *InterruptHook; + }; + + class Driver + { + private: + Vector Drivers; + unsigned long DriverUIDs = 0; + + DriverCode CallDriverEntryPoint(void *fex); + + public: + DriverCode LoadDriver(uint64_t DriverAddress, uint64_t Size); + DriverCode StartDrivers(); + Driver(); + ~Driver(); + }; +} + +#endif // !__FENNIX_KERNEL_DRIVER_H__ diff --git a/kernel.h b/kernel.h index 23c6590b..5e9bc717 100644 --- a/kernel.h +++ b/kernel.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,11 @@ extern KernelConfig Config; extern Tasking::Task *TaskManager; extern Time::time *TimeManager; extern FileSystem::Virtual *vfs; +extern Driver::Driver *DriverManager; + +#define PEXIT(Code) TaskManager->GetCurrentProcess()->ExitCode = Code +#define TEXIT(Code) TaskManager->GetCurrentThread()->ExitCode = Code + #endif EXTERNC void KPrint(const char *format, ...);