From 51ea074b60e38d30c2892385aacd756b04d1dbdf Mon Sep 17 00:00:00 2001 From: EnderIce2 Date: Sun, 7 Jul 2024 03:14:54 +0300 Subject: [PATCH] Fix driver implementation --- core/driver/api.cpp | 952 ++++++++++++++---------- core/driver/daemon.cpp | 634 ++++++++++++++++ core/driver/driver.cpp | 551 +++++++------- exec/binary_parse.cpp | 1 + include/driver.hpp | 87 ++- include/filesystem.hpp | 11 +- include/interface/aip.h | 259 +++++++ include/{cbuf.hpp => interface/audio.h} | 32 +- include/interface/device.h | 74 ++ include/interface/driver.h | 237 +----- include/interface/fs.h | 57 +- include/interface/input.h | 234 ++++++ include/interface/network.h | 29 + include/interface/pci.h | 184 +++++ include/ring.hpp | 124 +++ include/types.h | 63 +- kernel_thread.cpp | 11 +- kshell/commands/cat.cpp | 49 +- kshell/commands/cd.cpp | 29 +- kshell/commands/ls.cpp | 167 +++-- kshell/commands/modinfo.cpp | 7 +- kshell/commands/tree.cpp | 120 +-- kshell/shell.cpp | 45 +- library/cbuf.cpp | 99 --- storage/cache.cpp | 158 +++- storage/filesystem.cpp | 162 ++-- storage/fs/ustar.cpp | 20 +- storage/virtual.cpp | 181 ++--- tasking/task.cpp | 2 +- 29 files changed, 3069 insertions(+), 1510 deletions(-) create mode 100644 core/driver/daemon.cpp create mode 100644 include/interface/aip.h rename include/{cbuf.hpp => interface/audio.h} (57%) create mode 100644 include/interface/device.h create mode 100644 include/interface/input.h create mode 100644 include/interface/network.h create mode 100644 include/interface/pci.h create mode 100644 include/ring.hpp delete mode 100644 library/cbuf.cpp diff --git a/core/driver/api.cpp b/core/driver/api.cpp index 7f2c6cb2..329ad3a3 100644 --- a/core/driver/api.cpp +++ b/core/driver/api.cpp @@ -19,10 +19,13 @@ #include #include #include +#include +#include +#include #include "../../kernel.h" -// #define DEBUG_API +#define DEBUG_API #ifdef DEBUG_API #define dbg_api(Format, ...) func(Format, ##__VA_ARGS__) @@ -30,222 +33,461 @@ #define dbg_api(Format, ...) #endif -using enum PCI::PCICommands; - -#define VMWARE_MAGIC 0x564D5868 /* hXMV */ -#define VMWARE_PORT 0x5658 -#define CMD_GETVERSION 0xA - -namespace Driver +namespace v0 { - int RegisterFunction(dev_t MajorID, void *Function, __driverRegFunc Type) + typedef int CriticalState; + + void KernelPrint(dev_t DriverID, const char *Format, va_list args) { - dbg_api("%d, %#lx, %d", MajorID, (uintptr_t)Function, Type); - - std::unordered_map &Drivers = - DriverManager->GetDrivers(); - - auto itr = Drivers.find(MajorID); - if (itr == Drivers.end()) - return -EINVAL; - - DriverObject *drv = &itr->second; - - switch (Type) - { - case _drf_Entry: - drv->Entry = (int (*)())Function; - debug("Entry %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); - break; - case _drf_Final: - drv->Final = (int (*)())Function; - debug("Finalize %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); - break; - case _drf_Panic: - drv->Panic = (int (*)())Function; - debug("Panic %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); - break; - case _drf_Probe: - drv->Probe = (int (*)())Function; - debug("Probe %#lx for %s", (uintptr_t)Function, drv->Path.c_str()); - break; - default: - assert(!"Invalid driver function type"); - } - return 0; - } - - int GetDriverInfo(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License) - { - dbg_api("%d, %s, %s, %s, %s, %s", MajorID, Name, Description, Author, Version, License); - - std::unordered_map &Drivers = - DriverManager->GetDrivers(); - - auto itr = Drivers.find(MajorID); - if (itr == Drivers.end()) - return -EINVAL; - - DriverObject *drv = &itr->second; - - strncpy(drv->Name, Name, sizeof(drv->Name)); - strncpy(drv->Description, Description, sizeof(drv->Description)); - strncpy(drv->Author, Author, sizeof(drv->Author)); - strncpy(drv->Version, Version, sizeof(drv->Version)); - strncpy(drv->License, License, sizeof(drv->License)); - return 0; - } - - /* --------- */ - - int RegisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler) - { - dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler); - - std::unordered_map &Drivers = - DriverManager->GetDrivers(); - - auto itr = Drivers.find(MajorID); - if (itr == Drivers.end()) - return -EINVAL; - - DriverObject *drv = &itr->second; - - if (drv->InterruptHandlers->contains(IRQ)) - return -EEXIST; - - Interrupts::AddHandler((void (*)(CPU::TrapFrame *))Handler, IRQ); - drv->InterruptHandlers->insert(std::pair(IRQ, Handler)); - return 0; - } - - int OverrideInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler) - { - dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler); - - debug("Overriding IRQ %d with %#lx", IRQ, Handler); - - std::unordered_map &Drivers = - DriverManager->GetDrivers(); - - foreach (auto &var in Drivers) - { - DriverObject *drv = &var.second; - - foreach (auto &ih in * drv->InterruptHandlers) - { - if (ih.first == IRQ) - { - debug("Removing IRQ %d: %#lx for %s", IRQ, (uintptr_t)ih.second, drv->Path.c_str()); - Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))ih.second, IRQ); - drv->InterruptHandlers->erase(IRQ); - break; - } - } - } - - return RegisterInterruptHandler(MajorID, IRQ, Handler); - } - - int UnregisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler) - { - dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler); - - std::unordered_map &Drivers = - DriverManager->GetDrivers(); - - auto itr = Drivers.find(MajorID); - if (itr == Drivers.end()) - return -EINVAL; - - DriverObject *drv = &itr->second; - Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, IRQ); - drv->InterruptHandlers->erase(IRQ); - return 0; - } - - int UnregisterAllInterruptHandlers(dev_t MajorID, void *Handler) - { - dbg_api("%d, %#lx", MajorID, Handler); - - std::unordered_map &Drivers = - DriverManager->GetDrivers(); - - auto itr = Drivers.find(MajorID); - if (itr == Drivers.end()) - return -EINVAL; - - DriverObject *drv = &itr->second; - foreach (auto &i in * drv->InterruptHandlers) - { - Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, i.first); - debug("Removed IRQ %d: %#lx for %s", i.first, (uintptr_t)Handler, drv->Path.c_str()); - } - drv->InterruptHandlers->clear(); - return 0; - } - - /* --------- */ - - void d_KPrint(dev_t MajorID, const char *Format, va_list args) - { - dbg_api("%d %s, %#lx", MajorID, Format, args); + dbg_api("%d, %s, %#lx", DriverID, Format, args); _KPrint(Format, args); } - void KernelLog(dev_t MajorID, const char *Format, va_list args) + void KernelLog(dev_t DriverID, const char *Format, va_list args) { - dbg_api("%d, %s, %#lx", MajorID, Format, args); + dbg_api("%d, %s, %#lx", DriverID, Format, args); - fctprintf(uart_wrapper, nullptr, "DRVER| %ld: ", MajorID); + fctprintf(uart_wrapper, nullptr, "DRVER| %ld: ", DriverID); vfctprintf(uart_wrapper, nullptr, Format, args); uart_wrapper('\n', nullptr); } /* --------- */ - void *RequestPages(dev_t MajorID, size_t Pages) + CriticalState EnterCriticalSection(dev_t DriverID) { - dbg_api("%d, %d", MajorID, Pages); + dbg_api("%d", DriverID); - std::unordered_map &Drivers = - DriverManager->GetDrivers(); - auto itr = Drivers.find(MajorID); - assert(itr != Drivers.end()); + CriticalState cs; - return itr->second.vma->RequestPages(Pages); +#if defined(__i386__) || defined(__x86_64__) + + uintptr_t Flags; +#if defined(__x86_64__) + asmv("pushfq"); + asmv("popq %0" + : "=r"(Flags)); +#else + asmv("pushfl"); + asmv("popl %0" + : "=r"(Flags)); +#endif + cs = Flags & (1 << 9); + asmv("cli"); + +#elif defined(__arm__) || defined(__aarch64__) + + uintptr_t Flags; + asmv("mrs %0, cpsr" + : "=r"(Flags)); + cs = Flags & (1 << 7); + asmv("cpsid i"); + +#endif + + return cs; } - void FreePages(dev_t MajorID, void *Pointer, size_t Pages) + void LeaveCriticalSection(dev_t DriverID, CriticalState PreviousState) { - dbg_api("%d, %#lx, %d", MajorID, Pointer, Pages); + dbg_api("%d, %d", DriverID, PreviousState); - std::unordered_map &Drivers = +#if defined(__i386__) || defined(__x86_64__) + + if (PreviousState) + asmv("sti"); + +#elif defined(__arm__) || defined(__aarch64__) + + if (PreviousState) + asmv("cpsie i"); + +#endif + } + + int RegisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler) + { + dbg_api("%d, %d, %#lx", DriverID, IRQ, Handler); + + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(DriverID); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", DriverID); + const Driver::DriverObject *drv = &it->second; + + if (drv->InterruptHandlers->contains(IRQ)) + return -EEXIST; + + Interrupts::AddHandler((void (*)(CPU::TrapFrame *))Handler, IRQ); + auto ih = drv->InterruptHandlers; + ih->insert(std::pair(IRQ, Handler)); + return 0; + } + + int OverrideInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler) + { + dbg_api("%d, %d, %#lx", DriverID, IRQ, Handler); + + debug("Overriding IRQ %d with %#lx", IRQ, Handler); + + std::unordered_map &drivers = DriverManager->GetDrivers(); - auto itr = Drivers.find(MajorID); + for (auto &var : drivers) + { + Driver::DriverObject *drv = &var.second; + for (const auto &ih : *drv->InterruptHandlers) + { + if (ih.first != IRQ) + continue; + + debug("Removing IRQ %d: %#lx for %s", IRQ, (uintptr_t)ih.second, drv->Path.c_str()); + Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))ih.second, IRQ); + drv->InterruptHandlers->erase(IRQ); + break; + } + } + + return RegisterInterruptHandler(DriverID, IRQ, Handler); + } + + int UnregisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler) + { + dbg_api("%d, %d, %#lx", DriverID, IRQ, Handler); + + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(DriverID); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", DriverID); + const Driver::DriverObject *drv = &it->second; + + Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, IRQ); + auto ih = drv->InterruptHandlers; + ih->erase(IRQ); + return 0; + } + + int UnregisterAllInterruptHandlers(dev_t DriverID, void *Handler) + { + dbg_api("%d, %#lx", DriverID, Handler); + + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(DriverID); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", DriverID); + const Driver::DriverObject *drv = &it->second; + + for (auto &i : *drv->InterruptHandlers) + { + Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, i.first); + debug("Removed IRQ %d: %#lx for %s", i.first, (uintptr_t)Handler, drv->Path.c_str()); + } + auto ih = drv->InterruptHandlers; + ih->clear(); + return 0; + } + + /* --------- */ + + dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root) + { + dbg_api("%d, %#lx, %#lx", DriverID, Info, Root); + + return fs->RegisterFileSystem(Info, Root); + } + + int UnregisterFileSystem(dev_t DriverID, dev_t Device) + { + dbg_api("%d, %d", DriverID, Device); + + return fs->UnregisterFileSystem(Device); + } + + /* --------- */ + + pid_t CreateKernelProcess(dev_t DriverID, const char *Name) + { + dbg_api("%d, %s", DriverID, Name); + + Tasking::PCB *pcb = TaskManager->CreateProcess(nullptr, Name, Tasking::System, + true, 0, 0); + + return pcb->ID; + } + + pid_t CreateKernelThread(dev_t DriverID, pid_t pId, const char *Name, void *EntryPoint, void *Argument) + { + dbg_api("%d, %d, %s, %#lx, %#lx", DriverID, pId, Name, EntryPoint, Argument); + + Tasking::PCB *parent = TaskManager->GetProcessByID(pId); + if (!parent) + return -EINVAL; + + CriticalSection cs; + Tasking::TCB *tcb = TaskManager->CreateThread(parent, (Tasking::IP)EntryPoint); + if (Argument) + tcb->SYSV_ABI_Call((uintptr_t)Argument); + tcb->Rename(Name); + return tcb->ID; + } + + pid_t GetCurrentProcess(dev_t DriverID) + { + dbg_api("%d", DriverID); + + return TaskManager->GetCurrentProcess()->ID; + } + + int KillProcess(dev_t DriverID, pid_t pId, int ExitCode) + { + dbg_api("%d, %d, %d", DriverID, pId, ExitCode); + + Tasking::PCB *pcb = TaskManager->GetProcessByID(pId); + if (!pcb) + return -EINVAL; + TaskManager->KillProcess(pcb, (Tasking::KillCode)ExitCode); + return 0; + } + + int KillThread(dev_t DriverID, pid_t tId, pid_t pId, int ExitCode) + { + dbg_api("%d, %d, %d", DriverID, tId, ExitCode); + + Tasking::TCB *tcb = TaskManager->GetThreadByID(tId, TaskManager->GetProcessByID(pId)); + if (!tcb) + return -EINVAL; + TaskManager->KillThread(tcb, (Tasking::KillCode)ExitCode); + return 0; + } + + void Yield(dev_t DriverID) + { + dbg_api("%d", DriverID); + + TaskManager->Yield(); + } + + void Sleep(dev_t DriverID, uint64_t Milliseconds) + { + dbg_api("%d, %d", DriverID, Milliseconds); + + TaskManager->Sleep(Milliseconds); + } + + /* --------- */ + + void PIC_EOI(dev_t DriverID, uint8_t IRQ) + { + dbg_api("%d, %d", DriverID, IRQ); + + if (IRQ >= 8) + outb(PIC2_CMD, _PIC_EOI); + outb(PIC1_CMD, _PIC_EOI); + } + + void IRQ_MASK(dev_t DriverID, uint8_t IRQ) + { + dbg_api("%d, %d", DriverID, IRQ); + + uint16_t port; + uint8_t value; + + if (IRQ < 8) + port = PIC1_DATA; + else + { + port = PIC2_DATA; + IRQ -= 8; + } + + value = inb(port) | (1 << IRQ); + outb(port, value); + } + + void IRQ_UNMASK(dev_t DriverID, uint8_t IRQ) + { + dbg_api("%d, %d", DriverID, IRQ); + + uint16_t port; + uint8_t value; + + if (IRQ < 8) + port = PIC1_DATA; + else + { + port = PIC2_DATA; + IRQ -= 8; + } + + value = inb(port) & ~(1 << IRQ); + outb(port, value); + } + + void PS2Wait(dev_t DriverID, const bool Output) + { + dbg_api("%d, %d", DriverID, Output); + + int Timeout = 100000; + PS2_STATUSES Status = {.Raw = inb(PS2_STATUS)}; + while (Timeout--) + { + if (!Output) /* FIXME: Reverse? */ + { + if (Status.OutputBufferFull == 0) + return; + } + else + { + if (Status.InputBufferFull == 0) + return; + } + Status.Raw = inb(PS2_STATUS); + } + + warn("PS/2 controller timeout! (Status: %#x, %d)", Status, Output); + } + + void PS2WriteCommand(dev_t DriverID, uint8_t Command) + { + dbg_api("%d, %d", DriverID, Command); + + WaitInput; + outb(PS2_CMD, Command); + } + + void PS2WriteData(dev_t DriverID, uint8_t Data) + { + dbg_api("%d, %d", DriverID, Data); + + WaitInput; + outb(PS2_DATA, Data); + } + + uint8_t PS2ReadData(dev_t DriverID) + { + dbg_api("%d", DriverID); + + WaitOutput; + return inb(PS2_DATA); + } + + uint8_t PS2ReadStatus(dev_t DriverID) + { + dbg_api("%d", DriverID); + + WaitOutput; + return inb(PS2_STATUS); + } + + uint8_t PS2ReadAfterACK(dev_t DriverID) + { + dbg_api("%d", DriverID); + + uint8_t ret = PS2ReadData(DriverID); + while (ret == PS2_ACK) + { + WaitOutput; + ret = inb(PS2_DATA); + } + return ret; + } + + void PS2ClearOutputBuffer(dev_t DriverID) + { + dbg_api("%d", DriverID); + + PS2_STATUSES Status; + int timeout = 0x500; + while (timeout--) + { + Status.Raw = inb(PS2_STATUS); + if (Status.OutputBufferFull == 0) + return; + inb(PS2_DATA); + } + } + + int PS2ACKTimeout(dev_t DriverID) + { + dbg_api("%d", DriverID); + + int timeout = 0x500; + while (timeout > 0) + { + if (PS2ReadData(DriverID) == PS2_ACK) + return 0; + timeout--; + } + return -ETIMEDOUT; + } + + /* --------- */ + + void *AllocateMemory(dev_t DriverID, size_t Pages) + { + dbg_api("%d, %d", DriverID, Pages); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(DriverID); + assert(itr != Drivers.end()); + + void *ptr = itr->second.vma->RequestPages(Pages); + memset(ptr, 0, FROM_PAGES(Pages)); + return ptr; + } + + void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages) + { + dbg_api("%d, %#lx, %d", DriverID, Pointer, Pages); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(DriverID); assert(itr != Drivers.end()); itr->second.vma->FreePages(Pointer, Pages); } - /* --------- */ - - void AppendMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag) + void *MemoryCopy(dev_t DriverID, void *Destination, const void *Source, size_t Length) { - dbg_api("%d, %#lx, %d", MajorID, Address, Flag); + dbg_api("%d, %#lx, %#lx, %d", DriverID, Destination, Source, Length); - Memory::Virtual vmm(KernelPageTable); - vmm.GetPTE(Address)->raw |= Flag; + return memcpy(Destination, Source, Length); } - void RemoveMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag) + void *MemorySet(dev_t DriverID, void *Destination, int Value, size_t Length) { - dbg_api("%d, %#lx, %d", MajorID, Address, Flag); + dbg_api("%d, %#lx, %d, %d", DriverID, Destination, Value, Length); - Memory::Virtual vmm(KernelPageTable); - vmm.GetPTE(Address)->raw &= ~Flag; + return memset(Destination, Value, Length); + } + + void *MemoryMove(dev_t DriverID, void *Destination, const void *Source, size_t Length) + { + dbg_api("%d, %#lx, %#lx, %d", DriverID, Destination, Source, Length); + + return memmove(Destination, Source, Length); + } + + size_t StringLength(dev_t DriverID, const char String[]) + { + dbg_api("%d, %s", DriverID, String); + + return strlen(String); + } + + char *_strstr(dev_t DriverID, const char *Haystack, const char *Needle) + { + dbg_api("%d, %s, %s", DriverID, Haystack, Needle); + + return (char *)strstr(Haystack, Needle); } void MapPages(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags) @@ -264,87 +506,46 @@ namespace Driver vmm.Unmap(VirtualAddress, Pages); } - /* --------- */ - - pid_t CreateKernelProcess(dev_t MajorID, const char *Name) + void AppendMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag) { - dbg_api("%d, %s", MajorID, Name); + dbg_api("%d, %#lx, %d", MajorID, Address, Flag); - Tasking::PCB *pcb = TaskManager->CreateProcess(nullptr, Name, Tasking::System, - true, 0, 0); - - return pcb->ID; + Memory::Virtual vmm(KernelPageTable); + vmm.GetPTE(Address)->raw |= Flag; } - pid_t CreateKernelThread(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument) + void RemoveMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag) { - dbg_api("%d, %d, %s, %#lx, %#lx", MajorID, pId, Name, EntryPoint, Argument); + dbg_api("%d, %#lx, %d", MajorID, Address, Flag); - Tasking::PCB *parent = TaskManager->GetProcessByID(pId); - if (!parent) - return -EINVAL; - - CriticalSection cs; - Tasking::TCB *tcb = TaskManager->CreateThread(parent, (Tasking::IP)EntryPoint); - if (Argument) - tcb->SYSV_ABI_Call((uintptr_t)Argument); - tcb->Rename(Name); - return tcb->ID; + Memory::Virtual vmm(KernelPageTable); + vmm.GetPTE(Address)->raw &= ~Flag; } - pid_t GetCurrentProcess(dev_t MajorID) + void *Znwm(size_t Size) { - dbg_api("%d", MajorID); + dbg_api("%d", Size); - return TaskManager->GetCurrentProcess()->ID; + return malloc(Size); } - int KillProcess(dev_t MajorID, pid_t pId, int ExitCode) + void ZdlPvm(void *Pointer, size_t Size) { - dbg_api("%d, %d, %d", MajorID, pId, ExitCode); + dbg_api("%d, %#lx", Pointer, Size); - Tasking::PCB *pcb = TaskManager->GetProcessByID(pId); - if (!pcb) - return -EINVAL; - TaskManager->KillProcess(pcb, (Tasking::KillCode)ExitCode); - return 0; - } - - int KillThread(dev_t MajorID, pid_t tId, pid_t pId, int ExitCode) - { - dbg_api("%d, %d, %d", MajorID, tId, ExitCode); - - Tasking::TCB *tcb = TaskManager->GetThreadByID(tId, TaskManager->GetProcessByID(pId)); - if (!tcb) - return -EINVAL; - TaskManager->KillThread(tcb, (Tasking::KillCode)ExitCode); - return 0; - } - - void Yield(dev_t MajorID) - { - dbg_api("%d", MajorID); - - TaskManager->Yield(); - } - - void Sleep(dev_t MajorID, uint64_t Milliseconds) - { - dbg_api("%d, %d", MajorID, Milliseconds); - - TaskManager->Sleep(Milliseconds); + free(Pointer); } /* --------- */ - __PCIArray *GetPCIDevices(dev_t MajorID, uint16_t _Vendors[], uint16_t _Devices[]) + __PCIArray *GetPCIDevices(dev_t DriverID, uint16_t _Vendors[], uint16_t _Devices[]) { - dbg_api("%d, %#lx, %#lx", MajorID, _Vendors, _Devices); + dbg_api("%d, %#lx, %#lx", DriverID, _Vendors, _Devices); - std::unordered_map &Drivers = + std::unordered_map &Drivers = DriverManager->GetDrivers(); - auto itr = Drivers.find(MajorID); + auto itr = Drivers.find(DriverID); if (itr == Drivers.end()) return nullptr; @@ -394,11 +595,12 @@ namespace Driver return head; } - void InitializePCI(dev_t MajorID, void *_Header) + void InitializePCI(dev_t DriverID, void *_Header) { - dbg_api("%d, %#lx", MajorID, _Header); + dbg_api("%d, %#lx", DriverID, _Header); - PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header; + PCI::PCIDevice *__device = (PCI::PCIDevice *)_Header; + PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)__device->Header; debug("Header Type: %d", Header->HeaderType); switch (Header->HeaderType) @@ -523,11 +725,12 @@ namespace Driver Header->Command &= ~PCI_COMMAND_INTX_DISABLE; } - uint32_t GetBAR(dev_t MajorID, uint8_t i, void *_Header) + uint32_t GetBAR(dev_t DriverID, uint8_t i, void *_Header) { - dbg_api("%d, %d, %#lx", MajorID, i, _Header); + dbg_api("%d, %d, %#lx", DriverID, i, _Header); - PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header; + PCI::PCIDevice *__device = (PCI::PCIDevice *)_Header; + PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)__device->Header; switch (Header->HeaderType) { @@ -580,154 +783,44 @@ namespace Driver } } - /* --------- */ - - void *api__memcpy(dev_t MajorID, void *Destination, const void *Source, size_t Length) + uint8_t iLine(dev_t DriverID, PCIDevice *Device) { - dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length); + dbg_api("%d, %#lx", DriverID, Device); - return memcpy(Destination, Source, Length); + PCIHeader0 *Header = (PCIHeader0 *)Device->Header; + return Header->InterruptLine; } - void *api__memset(dev_t MajorID, void *Destination, int Value, size_t Length) + uint8_t iPin(dev_t DriverID, PCIDevice *Device) { - dbg_api("%d, %#lx, %d, %d", MajorID, Destination, Value, Length); + dbg_api("%d, %#lx", DriverID, Device); - return memset(Destination, Value, Length); - } - - void *api__memmove(dev_t MajorID, void *Destination, const void *Source, size_t Length) - { - dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length); - - return memmove(Destination, Source, Length); - } - - int api__memcmp(dev_t MajorID, const void *Left, const void *Right, size_t Length) - { - dbg_api("%d, %#lx, %#lx, %d", MajorID, Left, Right, Length); - - return memcmp(Left, Right, Length); - } - - size_t api__strlen(dev_t MajorID, const char *String) - { - dbg_api("%d, %s", MajorID, String); - - return strlen(String); - } - - char *api__strcpy(dev_t MajorID, char *Destination, const char *Source) - { - dbg_api("%d, %#lx, %s", MajorID, Destination, Source); - - return strcpy(Destination, Source); - } - - char *api__strcat(dev_t MajorID, char *Destination, const char *Source) - { - dbg_api("%d, %#lx, %s", MajorID, Destination, Source); - - return strcat(Destination, Source); - } - - int api__strcmp(dev_t MajorID, const char *Left, const char *Right) - { - dbg_api("%d, %s, %s", MajorID, Left, Right); - - return strcmp(Left, Right); - } - - int api__strncmp(dev_t MajorID, const char *Left, const char *Right, size_t Length) - { - dbg_api("%d, %s, %s, %d", MajorID, Left, Right, Length); - - return strncmp(Left, Right, Length); - } - - char *api__strchr(dev_t MajorID, const char *String, int Character) - { - dbg_api("%d, %s, %d", MajorID, String, Character); - - return strchr(String, Character); - } - - char *api__strrchr(dev_t MajorID, const char *String, int Character) - { - dbg_api("%d, %s, %d", MajorID, String, Character); - - stub; - return nullptr; - // return strrchr(String, Character); - } - - char *api__strstr(dev_t MajorID, const char *Haystack, const char *Needle) - { - dbg_api("%d, %s, %s", MajorID, Haystack, Needle); - - return strstr(Haystack, Needle); + PCIHeader0 *Header = (PCIHeader0 *)Device->Header; + return Header->InterruptPin; } /* --------- */ - void PopulateDriverAPI(void *API) + dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations) { - __driverAPI *api = (__driverAPI *)API; + dbg_api("%d, %d, %#lx", DriverID, Type, Operations); - api->RegisterFunction = RegisterFunction; - api->GetDriverInfo = GetDriverInfo; - - api->RegisterInterruptHandler = RegisterInterruptHandler; - api->OverrideInterruptHandler = OverrideInterruptHandler; - api->UnregisterInterruptHandler = UnregisterInterruptHandler; - api->UnregisterAllInterruptHandlers = UnregisterAllInterruptHandlers; - - api->KPrint = d_KPrint; - api->KernelLog = KernelLog; - - api->RequestPages = RequestPages; - api->FreePages = FreePages; - - api->AppendMapFlag = AppendMapFlag; - api->RemoveMapFlag = RemoveMapFlag; - api->MapPages = MapPages; - api->UnmapPages = UnmapPages; - - api->CreateKernelProcess = CreateKernelProcess; - api->CreateKernelThread = CreateKernelThread; - api->GetCurrentProcess = GetCurrentProcess; - api->KillProcess = KillProcess; - api->KillThread = KillThread; - api->Yield = Yield; - api->Sleep = Sleep; - - api->GetPCIDevices = GetPCIDevices; - api->InitializePCI = InitializePCI; - api->GetBAR = GetBAR; - - api->memcpy = api__memcpy; - api->memset = api__memset; - api->memmove = api__memmove; - api->memcmp = api__memcmp; - api->strlen = api__strlen; - api->strcpy = api__strcpy; - api->strcat = api__strcat; - api->strcmp = api__strcmp; - api->strncmp = api__strncmp; - api->strchr = api__strchr; - api->strrchr = api__strrchr; - api->strstr = api__strstr; + return DriverManager->RegisterDevice(DriverID, Type, Operations); } -} -dev_t __api_RegisterFileSystem(FileSystemInfo *Info, struct Inode *Root) -{ - return fs->RegisterFileSystem(Info, Root); -} + int UnregisterDevice(dev_t DriverID, dev_t Device) + { + dbg_api("%d, %d", DriverID, Device); -int __api_UnregisterFileSystem(dev_t Device) -{ - return fs->UnregisterFileSystem(Device); + return DriverManager->UnregisterDevice(DriverID, Device); + } + + int ReportInputEvent(dev_t DriverID, InputReport *Report) + { + dbg_api("%d, %#lx", DriverID, Report); + + return DriverManager->ReportInputEvent(DriverID, Report); + } } struct APISymbols @@ -736,11 +829,96 @@ struct APISymbols void *Function; }; -static struct APISymbols APISymbols[] = { - {"RegisterFileSystem", (void *)__api_RegisterFileSystem}, - {"UnregisterFileSystem", (void *)__api_UnregisterFileSystem}, +static struct APISymbols APISymbols_v0[] = { + {"__KernelPrint", (void *)v0::KernelPrint}, + {"__KernelLog", (void *)v0::KernelLog}, + + {"__EnterCriticalSection", (void *)v0::EnterCriticalSection}, + {"__LeaveCriticalSection", (void *)v0::LeaveCriticalSection}, + + {"__RegisterInterruptHandler", (void *)v0::RegisterInterruptHandler}, + {"__OverrideInterruptHandler", (void *)v0::OverrideInterruptHandler}, + {"__UnregisterInterruptHandler", (void *)v0::UnregisterInterruptHandler}, + {"__UnregisterAllInterruptHandlers", (void *)v0::UnregisterAllInterruptHandlers}, + + {"__RegisterFileSystem", (void *)v0::RegisterFileSystem}, + {"__UnregisterFileSystem", (void *)v0::UnregisterFileSystem}, + + {"__CreateKernelProcess", (void *)v0::CreateKernelProcess}, + {"__CreateKernelThread", (void *)v0::CreateKernelThread}, + {"__GetCurrentProcess", (void *)v0::GetCurrentProcess}, + {"__KillProcess", (void *)v0::KillProcess}, + {"__KillThread", (void *)v0::KillThread}, + {"__Yield", (void *)v0::Yield}, + {"__Sleep", (void *)v0::Sleep}, + + {"__PIC_EOI", (void *)v0::PIC_EOI}, + {"__IRQ_MASK", (void *)v0::IRQ_MASK}, + {"__IRQ_UNMASK", (void *)v0::IRQ_UNMASK}, + {"__PS2Wait", (void *)v0::PS2Wait}, + {"__PS2WriteCommand", (void *)v0::PS2WriteCommand}, + {"__PS2WriteData", (void *)v0::PS2WriteData}, + {"__PS2ReadData", (void *)v0::PS2ReadData}, + {"__PS2ReadStatus", (void *)v0::PS2ReadStatus}, + {"__PS2ReadAfterACK", (void *)v0::PS2ReadAfterACK}, + {"__PS2ClearOutputBuffer", (void *)v0::PS2ClearOutputBuffer}, + {"__PS2ACKTimeout", (void *)v0::PS2ACKTimeout}, + + {"__AllocateMemory", (void *)v0::AllocateMemory}, + {"__FreeMemory", (void *)v0::FreeMemory}, + {"__MemoryCopy", (void *)v0::MemoryCopy}, + {"__MemorySet", (void *)v0::MemorySet}, + {"__MemoryMove", (void *)v0::MemoryMove}, + {"__StringLength", (void *)v0::StringLength}, + {"__strstr", (void *)v0::_strstr}, + {"__MapPages", (void *)v0::MapPages}, + {"__UnmapPages", (void *)v0::UnmapPages}, + {"__AppendMapFlag", (void *)v0::AppendMapFlag}, + {"__RemoveMapFlag", (void *)v0::RemoveMapFlag}, + {"_Znwm", (void *)v0::Znwm}, + {"_ZdlPvm", (void *)v0::ZdlPvm}, + + {"__GetPCIDevices", (void *)v0::GetPCIDevices}, + {"__InitializePCI", (void *)v0::InitializePCI}, + {"__GetBAR", (void *)v0::GetBAR}, + {"__iLine", (void *)v0::iLine}, + {"__iPin", (void *)v0::iPin}, + + {"__RegisterDevice", (void *)v0::RegisterDevice}, + {"__UnregisterDevice", (void *)v0::UnregisterDevice}, + {"__ReportInputEvent", (void *)v0::ReportInputEvent}, }; -/* Checking functions signatures */ -static_assert(std::is_same_v); -static_assert(std::is_same_v); +long __KernelUndefinedFunction(long arg0, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7) +{ + debug("%#lx, %#lx, %#lx, %#lx, %#lx, %#lx, %#lx, %#lx", + arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + assert(!"Undefined kernel driver API function called!"); + CPU::Stop(); +} + +void *GetSymbolByName(const char *Name, int Version) +{ + switch (Version) + { + case 0: + { + for (auto sym : APISymbols_v0) + { + if (strcmp(Name, sym.Name) != 0) + continue; + + debug("Symbol %s found in API version %d", Name, Version); + return sym.Function; + } + break; + } + default: + assert(!"Invalid API version"); + } + + error("Symbol %s not found in API version %d", Name, Version); + KPrint("Driver API symbol \"%s\" not found!", Name); + return (void *)__KernelUndefinedFunction; +} diff --git a/core/driver/daemon.cpp b/core/driver/daemon.cpp new file mode 100644 index 00000000..b9bfab00 --- /dev/null +++ b/core/driver/daemon.cpp @@ -0,0 +1,634 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kernel.h" + +using namespace vfs; + +namespace Driver +{ + /** + * maj = 0 + * min: + * 0 - + * 1 - /dev/null + * 2 - /dev/zero + * 3 - /dev/random + * 4 - /dev/mem + * + * maj = 1 + * min: + * 0 - /dev/input/keyboard + * 1 - /dev/input/mouse + * ..- /dev/input/eventX + */ + + int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) + { + auto Parent = (Manager::DeviceInode *)_Parent; + + const char *basename; + size_t length; + cwk_path_get_basename(Name, &basename, &length); + if (basename == NULL) + { + error("Invalid name %s", Name); + return -EINVAL; + } + + for (const auto &child : Parent->Children) + { + debug("Comparing %s with %s", child->Name.c_str(), basename); + if (strcmp(child->Name.c_str(), basename) != 0) + continue; + + *Result = &child->Node; + return 0; + } + + debug("Not found %s", Name); + return -ENOENT; + } + + int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result) + { + assert(_Parent != nullptr); + + /* We expect to be /dev or children of it */ + auto Parent = (Manager::DeviceInode *)_Parent; + auto _dev = new Manager::DeviceInode; + _dev->Parent = nullptr; + _dev->ParentInode = _Parent; + _dev->Name = Name; + _dev->Node.Mode = Mode; + _dev->Node.Index = Parent->Node.Index + Parent->Children.size(); + Parent->Children.push_back(_dev); + + *Result = &_dev->Node; + return 0; + } + + ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) + { + switch (Node->GetMajor()) + { + case 0: + { + switch (Node->GetMinor()) + { + case 1: /* /dev/null */ + { + return 0; + } + case 2: /* /dev/zero */ + { + if (Size <= 0) + return 0; + + memset(Buffer, 0, Size); + return Size; + } + case 3: /* /dev/random */ + { + if (Size <= 0) + return 0; + + if (Size < sizeof(uint64_t)) + { + uint8_t *buf = (uint8_t *)Buffer; + for (size_t i = 0; i < Size; i++) + buf[i] = (uint8_t)(Random::rand16() & 0xFF); + return Size; + } + + uint64_t *buf = (uint64_t *)Buffer; + for (size_t i = 0; i < Size / sizeof(uint64_t); i++) + buf[i] = Random::rand64(); + return Size; + } + case 4: /* /dev/mem */ + { + stub; + return 0; + } + default: + return -ENOENT; + }; + break; + } + case 1: + { + switch (Node->GetMinor()) + { + case 0: /* /dev/input/keyboard */ + { + if (Size < sizeof(KeyboardReport)) + return -EINVAL; + + size_t nReads = Size / sizeof(KeyboardReport); + + KeyboardReport *report = (KeyboardReport *)Buffer; + + while (DriverManager->GlobalKeyboardInputReports.Count() == 0) + TaskManager->Yield(); + + DriverManager->GlobalKeyboardInputReports.Read(report, nReads); + return sizeof(KeyboardReport) * nReads; + } + case 1: /* /dev/input/mouse */ + { + if (Size < sizeof(MouseReport)) + return -EINVAL; + + size_t nReads = Size / sizeof(MouseReport); + + MouseReport *report = (MouseReport *)Buffer; + + while (DriverManager->GlobalMouseInputReports.Count() == 0) + TaskManager->Yield(); + + DriverManager->GlobalMouseInputReports.Read(report, nReads); + return sizeof(MouseReport) * nReads; + } + default: + return -ENOENT; + }; + } + default: + { + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(Node->GetMajor()); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor()); + const Driver::DriverObject *drv = &it->second; + + auto dop = drv->DeviceOperations; + auto dOps = dop->find(Node->GetMinor()); + if (dOps == dop->end()) + ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor()); + AssertReturnError(dOps->second.Ops, -ENOTSUP); + AssertReturnError(dOps->second.Ops->Read, -ENOTSUP); + return dOps->second.Ops->Read(Node, Buffer, Size, Offset); + } + } + } + + ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) + { + switch (Node->GetMajor()) + { + case 0: + { + switch (Node->GetMinor()) + { + case 1: /* /dev/null */ + { + return Size; + } + case 2: /* /dev/zero */ + { + return Size; + } + case 3: /* /dev/random */ + { + return Size; + } + case 4: /* /dev/mem */ + { + stub; + return 0; + } + default: + return -ENOENT; + }; + } + case 1: + { + switch (Node->GetMinor()) + { + case 0: /* /dev/input/keyboard */ + { + return -ENOTSUP; + } + case 1: /* /dev/input/mouse */ + { + return -ENOTSUP; + } + default: + return -ENOENT; + }; + } + default: + { + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(Node->GetMajor()); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor()); + const Driver::DriverObject *drv = &it->second; + + auto dop = drv->DeviceOperations; + auto dOps = dop->find(Node->GetMinor()); + if (dOps == dop->end()) + ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor()); + AssertReturnError(dOps->second.Ops, -ENOTSUP); + AssertReturnError(dOps->second.Ops->Write, -ENOTSUP); + return dOps->second.Ops->Write(Node, Buffer, Size, Offset); + } + } + } + + __no_sanitize("alignment") + ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + { + auto Node = (Manager::DeviceInode *)_Node; + + off_t realOffset = Offset; + + size_t totalSize = 0; + uint16_t reclen = 0; + struct kdirent *ent = nullptr; + + if (Offset == 0) + { + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1); + if (totalSize + reclen >= Size) + return -EINVAL; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = Node->Node.Index; + ent->d_off = Offset++; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, "."); + totalSize += reclen; + } + + if (Offset <= 1) + { + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1); + if (totalSize + reclen >= Size) + { + if (realOffset == 1) + return -EINVAL; + return totalSize; + } + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + + if (Node->Parent) + ent->d_ino = Node->Parent->Node->Index; + else if (Node->ParentInode) + ent->d_ino = Node->ParentInode->Index; + else + { + warn("Parent is null for %s", Node->Name.c_str()); + ent->d_ino = Node->Node.Index; + } + ent->d_off = Offset++; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, ".."); + totalSize += reclen; + } + + if (!S_ISDIR(Node->Node.Mode)) + return -ENOTDIR; + + if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size()) + return -EINVAL; + + off_t entries = 0; + for (const auto &var : Node->Children) + { + if (var->Node.Offset < Offset) + continue; + + if (entries >= Entries) + break; + + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1); + + if (totalSize + reclen >= Size) + break; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = var->Node.Index; + ent->d_off = var->Node.Offset; + ent->d_reclen = reclen; + ent->d_type = IFTODT(var->Node.Mode); + strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str())); + + totalSize += reclen; + entries++; + } + + if (totalSize + sizeof(struct kdirent) >= Size) + return totalSize; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = 0; + ent->d_off = 0; + ent->d_reclen = 0; + ent->d_type = DT_UNKNOWN; + ent->d_name[0] = '\0'; + return totalSize; + } + + void ManagerDaemonWrapper() { DriverManager->Daemon(); } + + void Manager::Daemon() + { + while (true) + { + TaskManager->Sleep(1000); + } + } + + dev_t Manager::RegisterInputDevice(std::unordered_map *dop, + dev_t DriverID, size_t i, const InodeOperations *Operations) + { + std::string prefix = "event"; + for (size_t j = 0; j < 128; j++) + { + std::string deviceName = prefix + std::to_string(j); + FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode); + if (node) + continue; + + /* c rwx r-- r-- */ + mode_t mode = S_IRWXU | + S_IRGRP | + S_IROTH | + S_IFCHR; + + node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode); + node->Node->SetDevice(DriverID, i); + + DriverHandlers dh{}; + dh.Ops = Operations; + dh.Node = node->Node; + dh.InputReports = new RingBuffer(16); + dop->insert({i, std::move(dh)}); + return i; + } + + ReturnLogError(-1, "No available slots for device %d", DriverID); + return -1; /* -Werror=return-type */ + } + + dev_t Manager::RegisterBlockDevice(std::unordered_map *dop, + dev_t DriverID, size_t i, const InodeOperations *Operations) + { + std::string prefix = "event"; + for (size_t j = 0; j < 128; j++) + { + std::string deviceName = prefix + std::to_string(j); + FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode); + if (node) + continue; + + /* c rwx r-- r-- */ + mode_t mode = S_IRWXU | + S_IRGRP | + S_IROTH | + S_IFCHR; + + node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode); + node->Node->SetDevice(DriverID, i); + + DriverHandlers dh{}; + dh.Ops = Operations; + dh.Node = node->Node; + dh.InputReports = new RingBuffer(16); + dop->insert({i, std::move(dh)}); + return i; + } + + ReturnLogError(-1, "No available slots for device %d", DriverID); + return -1; /* -Werror=return-type */ + } + + dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations) + { + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(DriverID); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", DriverID); + const Driver::DriverObject *drv = &it->second; + + auto dop = drv->DeviceOperations; + for (size_t i = 0; i < 128; i++) + { + const auto dOps = dop->find(i); + const auto dOpsEnd = dop->end(); + if (dOps != dOpsEnd) + continue; + + DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK); + switch (devType) + { + case DEVICE_TYPE_INPUT: + return RegisterInputDevice(dop, DriverID, i, Operations); + case DEVICE_TYPE_BLOCK: + return RegisterBlockDevice(dop, DriverID, i, Operations); + default: + ReturnLogError(-1, "Invalid device type %d", Type); + } + } + + ReturnLogError(-1, "No available slots for device %d", DriverID); + } + + int Manager::UnregisterDevice(dev_t DriverID, dev_t Device) + { + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(DriverID); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", DriverID); + const Driver::DriverObject *drv = &it->second; + + auto dop = drv->DeviceOperations; + const auto dOps = dop->find(Device); + if (dOps == dop->end()) + ReturnLogError(-EINVAL, "Device %d not found", Device); + dop->erase(dOps); + fixme("remove eventX from /dev/input"); + fixme("delete InputReports"); + return 0; + } + + int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report) + { + std::unordered_map &drivers = + DriverManager->GetDrivers(); + const auto it = drivers.find(DriverID); + if (it == drivers.end()) + ReturnLogError(-EINVAL, "Driver %d not found", DriverID); + const Driver::DriverObject *drv = &it->second; + + auto dop = drv->DeviceOperations; + auto dOps = dop->find(Report->Device); + if (dOps == dop->end()) + ReturnLogError(-EINVAL, "Device %d not found", Report->Device); + + dOps->second.InputReports->Write(Report, 1); + + switch (Report->Type) + { + case INPUT_TYPE_KEYBOARD: + { + KeyboardReport *kReport = &Report->Keyboard; + GlobalKeyboardInputReports.Write(kReport, 1); + break; + } + case INPUT_TYPE_MOUSE: + { + MouseReport *mReport = &Report->Mouse; + GlobalMouseInputReports.Write(mReport, 1); + break; + } + default: + assert(!"Invalid input type"); + } + return 0; + } + + void Manager::InitializeDaemonFS() + { + dev_t MinorID = 0; + DeviceInode *_dev = new DeviceInode; + _dev->Name = "dev"; + + /* d rwx r-- r-- */ + mode_t mode = S_IRWXU | + S_IRGRP | + S_IROTH | + S_IFDIR; + Inode *dev = (Inode *)_dev; + dev->Mode = mode; + dev->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + + FileSystemInfo *fsi = new FileSystemInfo; + fsi->Name = "Driver Manager"; + fsi->RootName = "dev"; + fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + fsi->SuperOps = {}; + fsi->Ops.Lookup = __fs_Lookup; + fsi->Ops.Create = __fs_Create; + fsi->Ops.Read = __fs_Read; + fsi->Ops.Write = __fs_Write; + fsi->Ops.ReadDir = __fs_Readdir; + + dev->Device = fs->RegisterFileSystem(fsi, dev); + dev->SetDevice(0, MinorID++); + + devNode = fs->Mount(fs->GetRoot(0), dev, "/dev"); + _dev->Parent = devNode->Parent; + _dev->ParentInode = devNode->Parent->Node; + + /* d rwx r-- r-- */ + mode = S_IRWXU | + S_IRGRP | + S_IROTH | + S_IFDIR; + DeviceInode *input = new DeviceInode; + input->Parent = devNode; + input->ParentInode = devNode->Node; + input->Name = "input"; + input->Node.Device = dev->Device; + input->Node.Mode = mode; + input->Node.Flags = I_FLAG_CACHE_KEEP; + _dev->Children.push_back(input); + devInputNode = fs->GetByPath("input", devNode); + + auto createDevice = [](DeviceInode *p1, FileNode *p2, const std::string &name, dev_t maj, dev_t min, mode_t mode) + { + DeviceInode *device = new DeviceInode; + device->Parent = p2; + device->ParentInode = p2->Node; + device->Name = name; + device->Node.Device = p2->Node->Device; + device->Node.Mode = mode; + device->Node.SetDevice(maj, min); + device->Node.Flags = I_FLAG_CACHE_KEEP; + p1->Children.push_back(device); + }; + + /* c rw- rw- rw- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH | + S_IFCHR; + createDevice(_dev, devNode, "null", 0, MinorID++, mode); + + /* c rw- rw- rw- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH | + S_IFCHR; + createDevice(_dev, devNode, "zero", 0, MinorID++, mode); + + /* c rw- rw- rw- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH | + S_IFCHR; + createDevice(_dev, devNode, "random", 0, MinorID++, mode); + + /* c rw- r-- --- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | + + S_IFCHR; + createDevice(_dev, devNode, "mem", 0, MinorID++, mode); + + /* ------------------------------------------------------ */ + + MinorID = 0; + + /* c rw- r-- --- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | + + S_IFCHR; + createDevice(input, devInputNode, "keyboard", 1, MinorID++, mode); + + /* c rw- r-- --- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | + + S_IFCHR; + createDevice(input, devInputNode, "mouse", 1, MinorID++, mode); + } +} diff --git a/core/driver/driver.cpp b/core/driver/driver.cpp index 3db8f652..37ad0ff5 100644 --- a/core/driver/driver.cpp +++ b/core/driver/driver.cpp @@ -18,11 +18,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -56,32 +58,30 @@ namespace Driver continue; } - Memory::VirtualMemoryArea *dVma = new Memory::VirtualMemoryArea(thisProcess->PageTable); + DriverObject drvObj = {.BaseAddress = 0, + .EntryPoint = 0, + .vma = new Memory::VirtualMemoryArea(thisProcess->PageTable), + .Path = drvNode->Path, + .InterruptHandlers = new std::unordered_map(), + .DeviceOperations = new std::unordered_map(), + .ID = DriverIDCounter}; - uintptr_t EntryPoint, BaseAddress; - int err = this->LoadDriverFile(EntryPoint, BaseAddress, dVma, drvNode); + int err = this->LoadDriverFile(drvObj, drvNode); debug("err = %d (%s)", err, strerror(err)); if (err != 0) { error("Failed to load driver %s: %s", drvNode->Path.c_str(), strerror(err)); - delete dVma; + delete drvObj.vma; + delete drvObj.InterruptHandlers; + delete drvObj.DeviceOperations; continue; } - Drivers[DriverIDCounter++] = { - .BaseAddress = BaseAddress, - .EntryPoint = EntryPoint, - .vma = dVma, - .Path = drvNode->Path, - .InterruptHandlers = new std::unordered_map}; + debug("gdb: \"0x%lX\" %s", drvObj.BaseAddress, drvObj.Name); - dev_t countr = DriverIDCounter - 1; - const char *drvName; - size_t drvNameLen; - cwk_path_get_basename(drvNode->Path.c_str(), &drvName, &drvNameLen); - strncpy(Drivers[countr].Name, drvName, sizeof(Drivers[countr].Name)); + Drivers.insert({DriverIDCounter++, drvObj}); } } @@ -95,66 +95,54 @@ namespace Driver foreach (auto &var in Drivers) { - DriverObject *Drv = &var.second; - size_t dapiPgs = TO_PAGES(sizeof(__driverAPI)); - __driverAPI *dApi = (__driverAPI *)Drv->vma->RequestPages(dapiPgs); - debug("Driver API at %#lx-%#lx", dApi, dApi + sizeof(__driverAPI)); + DriverObject &Drv = var.second; - fixme("api version"); - dApi->APIVersion.Major = 0; - dApi->APIVersion.Minor = 0; - dApi->APIVersion.Patch = 0; - - dApi->MajorID = var.first; - dApi->Base = Drv->BaseAddress; - PopulateDriverAPI(dApi); - - debug("Calling driver %s at %#lx", Drv->Path.c_str(), Drv->EntryPoint); - int (*DrvInit)(__driverAPI *) = (int (*)(__driverAPI *))Drv->EntryPoint; - Drv->ErrorCode = DrvInit(dApi); - if (Drv->ErrorCode < 0) + debug("Calling driver %s at %#lx", Drv.Path.c_str(), Drv.EntryPoint); + int (*DrvInit)(dev_t) = (int (*)(dev_t))Drv.EntryPoint; + Drv.ErrorCode = DrvInit(Drv.ID); + if (Drv.ErrorCode < 0) { KPrint("FATAL: _start() failed for %s: %s", - Drv->Name, strerror(Drv->ErrorCode)); + Drv.Name, strerror(Drv.ErrorCode)); error("Failed to load driver %s: %s", - Drv->Path.c_str(), strerror(Drv->ErrorCode)); + Drv.Path.c_str(), strerror(Drv.ErrorCode)); - Drv->vma->FreeAllPages(); + Drv.vma->FreeAllPages(); continue; } - KPrint("Loading driver %s", Drv->Name); + KPrint("Loading driver %s", Drv.Name); debug("Calling Probe()=%#lx on driver %s", - Drv->Probe, Drv->Path.c_str()); - Drv->ErrorCode = Drv->Probe(); - if (Drv->ErrorCode < 0) + Drv.Probe, Drv.Path.c_str()); + Drv.ErrorCode = Drv.Probe(); + if (Drv.ErrorCode < 0) { KPrint("Probe() failed for %s: %s", - Drv->Name, strerror(Drv->ErrorCode)); + Drv.Name, strerror(Drv.ErrorCode)); error("Failed to probe driver %s: %s", - Drv->Path.c_str(), strerror(Drv->ErrorCode)); + Drv.Path.c_str(), strerror(Drv.ErrorCode)); - Drv->vma->FreeAllPages(); + Drv.vma->FreeAllPages(); continue; } debug("Calling driver Entry()=%#lx function on driver %s", - Drv->Entry, Drv->Path.c_str()); - Drv->ErrorCode = Drv->Entry(); - if (Drv->ErrorCode < 0) + Drv.Entry, Drv.Path.c_str()); + Drv.ErrorCode = Drv.Entry(); + if (Drv.ErrorCode < 0) { KPrint("Entry() failed for %s: %s", - Drv->Name, strerror(Drv->ErrorCode)); + Drv.Name, strerror(Drv.ErrorCode)); error("Failed to initialize driver %s: %s", - Drv->Path.c_str(), strerror(Drv->ErrorCode)); + Drv.Path.c_str(), strerror(Drv.ErrorCode)); - Drv->vma->FreeAllPages(); + Drv.vma->FreeAllPages(); continue; } - debug("Loaded driver %s", Drv->Path.c_str()); - Drv->Initialized = true; + debug("Loaded driver %s", Drv.Path.c_str()); + Drv.Initialized = true; } } @@ -182,9 +170,6 @@ namespace Driver } Drv->InterruptHandlers->clear(); } - - delete Drv->vma, Drv->vma = nullptr; - delete Drv->InterruptHandlers, Drv->InterruptHandlers = nullptr; } Drivers.clear(); } @@ -212,180 +197,229 @@ namespace Driver } } - int Manager::LoadDriverFile(uintptr_t &EntryPoint, uintptr_t &BaseAddress, - Memory::VirtualMemoryArea *dVma, FileNode *rDrv) + int Manager::LoadDriverFile(DriverObject &Drv, FileNode *File) { - Elf64_Ehdr ELFHeader; - rDrv->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0); - if (ELFHeader.e_type != ET_DYN) + trace("Loading driver %s in memory", File->Name.c_str()); + + Elf_Ehdr ELFHeader{}; + File->Read(&ELFHeader, sizeof(Elf_Ehdr), 0); + + AssertReturnError(ELFHeader.e_ident[EI_CLASS] == ELFCLASS64, -ENOEXEC); + AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC); + AssertReturnError(ELFHeader.e_ident[EI_OSABI] == ELFOSABI_SYSV, -ENOEXEC); + AssertReturnError(ELFHeader.e_ident[EI_ABIVERSION] == 0, -ENOEXEC); + AssertReturnError(ELFHeader.e_type == ET_DYN, -ENOEXEC); + AssertReturnError(ELFHeader.e_machine == EM_X86_64, -ENOEXEC); + AssertReturnError(ELFHeader.e_version == EV_CURRENT, -ENOEXEC); + AssertReturnError(ELFHeader.e_entry != 0x0, -ENOEXEC); + AssertReturnError(ELFHeader.e_shstrndx != SHN_UNDEF, -ENOEXEC); + Drv.EntryPoint = ELFHeader.e_entry; + + size_t segSize = 0; + Elf_Phdr phdr{}; + for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) { - error("Driver %s is not a shared object", rDrv->Path.c_str()); - return -ENOEXEC; - } - - trace("Loading driver %s in memory", rDrv->Name.c_str()); - - BaseAddress = 0; - { - Elf64_Phdr ProgramBreakHeader{}; - Elf64_Phdr ProgramHeader; - - size_t SegmentsSize = 0; - for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) + File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); + if (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC) { - rDrv->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); - - if (ProgramHeader.p_type == PT_LOAD || - ProgramHeader.p_type == PT_DYNAMIC) - { - if (SegmentsSize < ProgramHeader.p_vaddr + ProgramHeader.p_memsz) - { - SegmentsSize = ProgramHeader.p_vaddr + ProgramHeader.p_memsz; - ProgramBreakHeader = ProgramHeader; - } - } + if (segSize < phdr.p_vaddr + phdr.p_memsz) + segSize = phdr.p_vaddr + phdr.p_memsz; + continue; } - debug("SegmentsSize: %#lx", SegmentsSize); - /* TODO: Check if this is correct and/or it needs more - complex calculations & allocations */ - void *SegmentsAddress = dVma->RequestPages(TO_PAGES(SegmentsSize) + 1); - BaseAddress = (uintptr_t)SegmentsAddress; - debug("BaseAddress: %#lx, End: %#lx (%#lx)", BaseAddress, - BaseAddress + FROM_PAGES(TO_PAGES(SegmentsSize)), - SegmentsSize); - - for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) + if (phdr.p_type == PT_INTERP) { - rDrv->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); - - switch (ProgramHeader.p_type) + char interp[17]; + File->Read(interp, sizeof(interp), phdr.p_offset); + if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0) { - case PT_LOAD: - { - /* Because this is ET_DYN, we can load the segments - anywhere we want. */ - uintptr_t SegmentDestination = BaseAddress + ProgramHeader.p_vaddr; - - if (ProgramHeader.p_memsz == 0) - continue; - - debug("Copying PT_LOAD to %#lx-%#lx (%ld file bytes, %ld mem bytes)", - SegmentDestination, SegmentDestination + ProgramHeader.p_memsz, - ProgramHeader.p_filesz, ProgramHeader.p_memsz); - - if (ProgramHeader.p_filesz > 0) - { - rDrv->Read(SegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); - } - - if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) - { - void *zAddr = (void *)(SegmentDestination + ProgramHeader.p_filesz); - memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz); - } - break; - } - case PT_DYNAMIC: - { - /* PT_DYNAMIC contains the dynamic linking information for the - executable or shared library. */ - - uintptr_t DynamicSegmentDestination = BaseAddress + ProgramHeader.p_vaddr; - - if (ProgramHeader.p_memsz == 0) - continue; - - debug("Copying PT_DYNAMIC to %#lx-%#lx (%ld file bytes, %ld mem bytes)", - DynamicSegmentDestination, DynamicSegmentDestination + ProgramHeader.p_memsz, - ProgramHeader.p_filesz, ProgramHeader.p_memsz); - - if (ProgramHeader.p_filesz > 0) - { - rDrv->Read(DynamicSegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); - } - - if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) - { - void *zAddr = (void *)(DynamicSegmentDestination + ProgramHeader.p_filesz); - memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz); - } - break; - } - default: - { - fixme("Unhandled program header type: %#lx", - ProgramHeader.p_type); - break; - } + error("Interpreter is not /boot/fennix.elf"); + return -ENOEXEC; } } } + debug("segSize: %ld", segSize); - Elf64_Phdr ProgramHeader; - for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) + Drv.BaseAddress = (uintptr_t)Drv.vma->RequestPages(TO_PAGES(segSize) + 1); + Drv.EntryPoint += Drv.BaseAddress; + debug("Driver %s has entry point %#lx and base %#lx", + File->Name.c_str(), Drv.EntryPoint, Drv.BaseAddress); + + Elf64_Shdr sht_strtab{}; + Elf64_Shdr sht_symtab{}; + Elf_Shdr shstrtab{}; + Elf_Shdr shdr{}; + __DriverInfo driverInfo{}; + File->Read(&shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize)); + for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++) { - rDrv->Read(&ProgramHeader, sizeof(Elf64_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr))); + if (i == ELFHeader.e_shstrndx) + continue; - if (ProgramHeader.p_type == PT_DYNAMIC) + File->Read(&shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize)); + + switch (shdr.sh_type) { - Elf64_Dyn *Dynamic = (Elf64_Dyn *)(BaseAddress + ProgramHeader.p_vaddr); - Elf64_Dyn *RelaSize = nullptr; - Elf64_Dyn *PltRelSize = nullptr; + case SHT_PROGBITS: + break; + case SHT_SYMTAB: + sht_symtab = shdr; + continue; + case SHT_STRTAB: + sht_strtab = shdr; + continue; + case SHT_NULL: + default: + continue; + } - while (Dynamic->d_tag != DT_NULL) + char symName[16]; + File->Read(symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name); + if (strcmp(symName, ".driver.info") != 0) + continue; + + File->Read(&driverInfo, sizeof(__DriverInfo), shdr.sh_offset); + + /* Perform relocations */ + driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name); + driverInfo.Description = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Description); + driverInfo.Author = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Author); + driverInfo.License = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.License); + } + + for (size_t h = 0; h < (sht_symtab.sh_size / sizeof(Elf64_Sym)); h++) + { + Elf64_Sym symEntry{}; + uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf64_Sym)); + File->Read(&symEntry, sizeof(Elf64_Sym), symOffset); + + if (symEntry.st_name == 0) + continue; + + char symName[16]; + File->Read(symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name); + + switch (symEntry.st_shndx) + { + case SHN_UNDEF: + case SHN_ABS: + case SHN_LOPROC /* , SHN_LORESERVE and SHN_BEFORE */: + case SHN_AFTER: + case SHN_HIPROC: + case SHN_COMMON: + case SHN_HIRESERVE: + break; + default: + { + debug("shndx: %d", symEntry.st_shndx); + if (strcmp(symName, "DriverEntry") == 0) + Drv.Entry = (int (*)())(Drv.BaseAddress + symEntry.st_value); + else if (strcmp(symName, "DriverFinal") == 0) + Drv.Final = (int (*)())(Drv.BaseAddress + symEntry.st_value); + else if (strcmp(symName, "DriverPanic") == 0) + Drv.Panic = (int (*)())(Drv.BaseAddress + symEntry.st_value); + else if (strcmp(symName, "DriverProbe") == 0) + Drv.Probe = (int (*)())(Drv.BaseAddress + symEntry.st_value); + + debug("Found %s at %#lx", symName, symEntry.st_value); + break; + } + } + } + + for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) + { + File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); + + switch (phdr.p_type) + { + case PT_LOAD: + case PT_DYNAMIC: + { + if (phdr.p_memsz == 0) + continue; + + uintptr_t dest = Drv.BaseAddress + phdr.p_vaddr; + debug("Copying PHDR %#lx to %#lx-%#lx (%ld file bytes, %ld mem bytes)", + phdr.p_type, dest, dest + phdr.p_memsz, + phdr.p_filesz, phdr.p_memsz); + + if (phdr.p_filesz > 0) + File->Read(dest, phdr.p_filesz, phdr.p_offset); + + if (phdr.p_memsz - phdr.p_filesz > 0) { - switch (Dynamic->d_tag) - { - case DT_RELASZ: - RelaSize = Dynamic; - debug("RELA Size: %d", RelaSize->d_un.d_val / sizeof(Elf64_Rela)); + void *zero = (void *)(dest + phdr.p_filesz); + memset(zero, 0, phdr.p_memsz - phdr.p_filesz); + } - break; + if (phdr.p_type != PT_DYNAMIC) + break; + + Elf64_Dyn *dyn = (Elf64_Dyn *)(Drv.BaseAddress + phdr.p_vaddr); + Elf64_Dyn *relaSize = nullptr; + Elf64_Dyn *pltrelSize = nullptr; + + while (dyn->d_tag != DT_NULL) + { + switch (dyn->d_tag) + { case DT_PLTRELSZ: - PltRelSize = Dynamic; - debug("PLTRELSZ: %d", PltRelSize->d_un.d_val / sizeof(Elf64_Rela)); - + { + pltrelSize = dyn; break; + } + case DT_PLTGOT: + { + Elf_Addr *got = (Elf_Addr *)(Drv.BaseAddress + dyn->d_un.d_ptr); + got[1] = 0; + got[2] = 0; + break; + } + case DT_RELASZ: + { + relaSize = dyn; + break; + } + case DT_PLTREL: + { + AssertReturnError(dyn->d_un.d_val == DT_RELA, -ENOEXEC); + break; + } default: break; } - - Dynamic++; + dyn++; } - Dynamic = (Elf64_Dyn *)(BaseAddress + ProgramHeader.p_vaddr); - while (Dynamic->d_tag != DT_NULL) + dyn = (Elf64_Dyn *)(Drv.BaseAddress + phdr.p_vaddr); + while (dyn->d_tag != DT_NULL) { - switch (Dynamic->d_tag) + switch (dyn->d_tag) { case DT_RELA: /* .rela.dyn */ { - if (!RelaSize) - { - error("DT_RELASZ is not set"); - break; - } + AssertReturnError(relaSize != nullptr, -ENOEXEC); - Elf64_Rela *Rela = (Elf64_Rela *)(BaseAddress + Dynamic->d_un.d_ptr); - for (size_t i = 0; i < (RelaSize->d_un.d_val / sizeof(Elf64_Rela)); i++) + Elf64_Rela *rela = (Elf64_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr); + for (size_t i = 0; i < (relaSize->d_un.d_val / sizeof(Elf64_Rela)); i++) { - Elf64_Rela *r = &Rela[i]; - uintptr_t *RelocationAddress = (uintptr_t *)(BaseAddress + r->r_offset); - uintptr_t RelocationTarget = 0; + Elf64_Rela *r = &rela[i]; + uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset); + uintptr_t relocTarget = 0; switch (ELF64_R_TYPE(r->r_info)) { case R_X86_64_GLOB_DAT: case R_X86_64_JUMP_SLOT: { - RelocationTarget = BaseAddress; + relocTarget = Drv.BaseAddress; break; } case R_X86_64_RELATIVE: case R_X86_64_64: { - RelocationTarget = BaseAddress + r->r_addend; + relocTarget = Drv.BaseAddress + r->r_addend; break; } default: @@ -396,53 +430,40 @@ namespace Driver } } - *RelocationAddress = RelocationTarget; + *reloc = relocTarget; debug("Relocated %#lx to %#lx", - r->r_offset, *RelocationAddress); + r->r_offset, *reloc); } break; } - case DT_PLTREL: - { - if (Dynamic->d_un.d_val != DT_RELA) - error("DT_PLTREL is not DT_RELA"); - break; - } case DT_JMPREL: /* .rela.plt */ { - if (!PltRelSize) - { - error("DT_PLTRELSZ is not set"); - break; - } + AssertReturnError(pltrelSize != nullptr, -ENOEXEC); - std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_SYMTAB); - std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_STRTAB); - Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); - char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); - UNUSED(DynStr); + std::vector symtab = Execute::ELFGetDynamicTag_x86_64(File, DT_SYMTAB); + Elf64_Sym *symbols = (Elf64_Sym *)((uintptr_t)Drv.BaseAddress + symtab[0].d_un.d_ptr); - Elf64_Rela *Rela = (Elf64_Rela *)(BaseAddress + Dynamic->d_un.d_ptr); - for (size_t i = 0; i < (PltRelSize->d_un.d_val / sizeof(Elf64_Rela)); i++) + std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(File, DT_STRTAB); + char *DynStr = (char *)((uintptr_t)Drv.BaseAddress + StrTab[0].d_un.d_ptr); + + Elf64_Rela *rela = (Elf64_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr); + for (size_t i = 0; i < (pltrelSize->d_un.d_val / sizeof(Elf64_Rela)); i++) { - Elf64_Rela *r = &Rela[i]; - uintptr_t *RelocationAddress = (uintptr_t *)(BaseAddress + r->r_offset); - uintptr_t RelocationTarget = 0; + Elf64_Rela *r = &rela[i]; + uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset); switch (ELF64_R_TYPE(r->r_info)) { case R_X86_64_JUMP_SLOT: { - Elf64_Xword SymIndex = ELF64_R_SYM(r->r_info); - Elf64_Sym *Sym = _SymTab + SymIndex; + Elf64_Xword symIndex = ELF64_R_SYM(r->r_info); + Elf64_Sym *sym = symbols + symIndex; -#ifdef DEBUG - const char *SymbolName = DynStr + Sym->st_name; - debug("Symbol %s at %#lx", SymbolName, Sym->st_value); -#endif + const char *symName = DynStr + sym->st_name; + debug("Resolving symbol %s", symName); - RelocationTarget = BaseAddress + Sym->st_value; + *reloc = (uintptr_t)GetSymbolByName(symName, driverInfo.Version.APIVersion); break; } default: @@ -452,96 +473,48 @@ namespace Driver break; } } - - *RelocationAddress = RelocationTarget; - - debug("Relocated %#lx to %#lx", - r->r_offset, *RelocationAddress); } break; } - case DT_SYMTAB: - { - fixme("DT_SYMTAB"); + case DT_PLTGOT: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_PLTREL: break; - - std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_SYMTAB); - std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(rDrv, DT_STRTAB); - Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); - char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); - UNUSED(DynStr); - - size_t symtabEntrySize = 0; - Elf64_Dyn *entrySizeDyn = Dynamic; - while (entrySizeDyn->d_tag != DT_NULL) - { - if (entrySizeDyn->d_tag == DT_SYMENT) - { - symtabEntrySize = entrySizeDyn->d_un.d_val; - break; - } - entrySizeDyn++; - } - - if (symtabEntrySize == 0) - { - fixme("No information about symbol entry size"); - break; - } - - size_t numSymbols = Dynamic->d_un.d_val / symtabEntrySize; - - for (size_t i = 0; i < numSymbols; i++) - { - Elf64_Sym *s = &_SymTab[i]; - if (s->st_name == 0) - continue; - -#ifdef DEBUG - const char *SymbolName = (const char *)(DynStr + s->st_name); - debug("%d: Symbol %s at %#lx", i, SymbolName, s->st_value); -#endif - /** TODO: search for symbols and link */ - /** good use but it will not work only - * if we specify to default visibility but - * this will create more issues :/ */ - // if (strcmp(SymbolName, "DriverProbe") == 0) - // { - // Drivers[DriverIDCounter].Probe = (int (*)())(BaseAddress + s->st_value); - // debug("Found probe function at %#lx", Drivers[DriverIDCounter].Probe); - // } - } - break; - } default: { - fixme("Unhandled dynamic tag: %#lx", - Dynamic->d_tag); + fixme("Unhandled dynamic tag: %#lx", dyn->d_tag); break; } } - Dynamic++; + dyn++; } + break; + } + case PT_PHDR: + case PT_INTERP: + break; + default: + { + fixme("Unhandled program header type: %#lx", phdr.p_type); + break; + } } } - EntryPoint = ELFHeader.e_entry; - EntryPoint += BaseAddress; + AssertReturnError(driverInfo.Name != nullptr, -EFAULT); + strncpy(Drv.Name, driverInfo.Name, sizeof(Drv.Name)); + strncpy(Drv.Description, driverInfo.Description, sizeof(Drv.Description)); + strncpy(Drv.Author, driverInfo.Author, sizeof(Drv.Author)); + Drv.Version.Major = driverInfo.Version.Major; + Drv.Version.Minor = driverInfo.Version.Minor; + Drv.Version.Patch = driverInfo.Version.Patch; + strncpy(Drv.License, driverInfo.License, sizeof(Drv.License)); - debug("Driver %s has entry point %#lx and base %#lx", - rDrv->Path.c_str(), EntryPoint, BaseAddress); - - /* FIXME: Do not add to the KernelSymbolTable! */ - // Memory::SmartHeap sh(rDrv->Size); - // rDrv->seek(0, SEEK_SET); - // rDrv->read((uint8_t *)sh.Get(), rDrv->Size); - // KernelSymbolTable->AppendSymbols((uintptr_t)sh.Get(), BaseAddress); return 0; } - Manager::Manager() - { - } + Manager::Manager() { this->InitializeDaemonFS(); } Manager::~Manager() { diff --git a/exec/binary_parse.cpp b/exec/binary_parse.cpp index cf615359..ddcacdf3 100644 --- a/exec/binary_parse.cpp +++ b/exec/binary_parse.cpp @@ -100,6 +100,7 @@ namespace Execute BinaryType GetBinaryType(std::string Path) { FileNode *node = fs->GetByPath(Path.c_str(), nullptr); + assert(node != nullptr); return GetBinaryType(node); } } diff --git a/include/driver.hpp b/include/driver.hpp index f6db9ee4..4f5aa9e5 100644 --- a/include/driver.hpp +++ b/include/driver.hpp @@ -20,16 +20,21 @@ #include +#include +#include #include #include #include #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -38,20 +43,32 @@ namespace Driver char GetScanCode(uint8_t ScanCode, bool Upper); bool IsValidChar(uint8_t ScanCode); + struct DriverHandlers + { + const InodeOperations *Ops = nullptr; + struct Inode *Node = nullptr; + RingBuffer *InputReports; + }; + struct DriverObject { uintptr_t BaseAddress = 0; uintptr_t EntryPoint = 0; - Memory::VirtualMemoryArea *vma = nullptr; + Memory::VirtualMemoryArea *vma; /* Path has the same pointer as in the Node */ std::string Path; std::unordered_map *InterruptHandlers; + std::unordered_map *DeviceOperations; + dev_t ID = 0; char Name[32] = {'\0'}; char Description[64] = {'\0'}; char Author[32] = {'\0'}; - char Version[16] = {'\0'}; + struct + { + int Major, Minor, Patch; + } Version = {0, 0, 0}; char License[32] = {'\0'}; bool Initialized = false; int ErrorCode = 0; @@ -67,27 +84,81 @@ namespace Driver private: NewLock(ModuleInitLock); std::unordered_map Drivers; - dev_t DriverIDCounter = 0; - int LoadDriverFile(uintptr_t &EntryPoint, - uintptr_t &BaseAddress, - Memory::VirtualMemoryArea *dVma, - FileNode *rDrv); + /** + * 0 - generic null/zero/random/etc devices + * 1 - input/... devices + */ + dev_t DriverIDCounter = 2; + FileNode *devNode = nullptr; + FileNode *devInputNode = nullptr; + + int LoadDriverFile(DriverObject &Drv, FileNode *File); + + void InitializeDaemonFS(); + + dev_t RegisterInputDevice(std::unordered_map *, dev_t, size_t, const InodeOperations *); + dev_t RegisterBlockDevice(std::unordered_map *, dev_t, size_t, const InodeOperations *); public: + RingBuffer GlobalKeyboardInputReports; + RingBuffer GlobalMouseInputReports; + + struct DeviceInode + { + struct Inode Node; + FileNode *Parent; + Inode *ParentInode; + std::string Name; + std::vector Children; + }; + std::unordered_map & GetDrivers() { return Drivers; } + void Daemon(); void PreloadDrivers(); void LoadAllDrivers(); void UnloadAllDrivers(); void Panic(); + /** Prefixes: + * - dsk (any disk device) + * - dsk0p0 (disk 0, partition 0) + * - blk (block device) + * - eth (Ethernet device) + * - wlan (Wireless LAN device) + * - lo (Loopback device) + * - kb (Keyboard device) + * - ms (Mouse device) + * - js (Joystick device) + * - tp (Touchpad device) + * - tc (Touchscreen device) + * - cam (Camera device) + * - spk (Speaker device) + * - mic (Microphone device) + * - snd (Sound device) + * - tty (Serial device) + * - lp (Parallel device) + * - gpu (Graphics device) + * - fb (Framebuffer device) + * - usb (USB device) + * - usb0dsk0p0 (USB 0, disk 0, partition 0; for USB storage) + */ + dev_t CreateIncrementalDevice(dev_t DriverID, const std::string &Prefix, mode_t Mode, InodeOperations *Ops); + + dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations); + int ReportInputEvent(dev_t DriverID, InputReport *Report); + + int UnregisterDevice(dev_t DriverID, dev_t Device); + Manager(); ~Manager(); }; - void PopulateDriverAPI(void *API); + void ManagerDaemonWrapper(); } +void *GetSymbolByName(const char *Name, int Version); + #endif // !__FENNIX_KERNEL_DRIVER_H__ diff --git a/include/filesystem.hpp b/include/filesystem.hpp index 5557b899..00ba11fd 100644 --- a/include/filesystem.hpp +++ b/include/filesystem.hpp @@ -37,6 +37,8 @@ static_assert(IFTODT(S_IFCHR) == DT_CHR); else \ return fsi->Ops.op(this->Node, ##__VA_ARGS__) +#define FSROOT(num) "\002root-" #num "\003" + class FileNode { public: @@ -83,6 +85,7 @@ namespace vfs { Inode Node; std::string Name; + std::string FriendlyName; std::vector Children; }; @@ -106,7 +109,8 @@ namespace vfs std::unordered_map DeviceMap; std::atomic_bool RegisterLock = false; - FileNode *__CacheRecursiveSearch(FileNode *, const char *, bool); + FileNode *CacheSearchReturnLast(FileNode *Parent, const char **Path); + FileNode *CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName); FileNode *CacheLookup(const char *Path); FileNode *CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode); @@ -114,6 +118,7 @@ namespace vfs public: vfsInode *FileSystemRoots = nullptr; + std::unordered_map FileRoots; bool PathIsRelative(const char *Path); bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); } @@ -140,7 +145,11 @@ namespace vfs FileNode *Create(FileNode *Parent, const char *Name, mode_t Mode); FileNode *ForceCreate(FileNode *Parent, const char *Name, mode_t Mode); + FileNode *Mount(FileNode *Parent, Inode *Node, const char *Path); + int Unmount(const char *Path); + FileNode *GetByPath(const char *Path, FileNode *Parent); + std::string GetByNode(FileNode *Node); FileNode *CreateLink(const char *Path, FileNode *Parent, const char *Target); FileNode *CreateLink(const char *Path, FileNode *Parent, FileNode *Target); bool PathExists(const char *Path, FileNode *Parent); diff --git a/include/interface/aip.h b/include/interface/aip.h new file mode 100644 index 00000000..9eebc58a --- /dev/null +++ b/include/interface/aip.h @@ -0,0 +1,259 @@ +/* + This file is part of Fennix Drivers. + + Fennix Drivers is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Drivers is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Drivers. If not, see . +*/ + +#ifndef __FENNIX_API_AIP_H__ +#define __FENNIX_API_AIP_H__ + +#include + +#define PIC1_CMD 0x20 +#define PIC1_DATA (PIC1_CMD + 1) +#define PIC2_CMD 0xA0 +#define PIC2_DATA (PIC2_CMD + 1) +#define _PIC_EOI 0x20 + +#define PS2_DATA 0x60 +#define PS2_STATUS 0x64 +#define PS2_CMD PS2_STATUS +#define PS2_ACK 0xFA +#define PS2_TEST_PASSED 0x55 +#define PS2_TEST_FAILED 0xFC + +#define PS2_CMD_READ_CONFIG 0x20 +#define PS2_CMD_READ_CONFIG_N(n) (PS2_CMD_READ_CONFIG + n) +#define PS2_CMD_WRITE_CONFIG 0x60 +#define PS2_CMD_WRITE_CONFIG_N(n) (PS2_CMD_WRITE_CONFIG + n) +#define PS2_CMD_DISABLE_PORT_2 0xA7 +#define PS2_CMD_ENABLE_PORT_2 0xA8 +#define PS2_CMD_TEST_PORT_2 0xA9 +#define PS2_CMD_TEST_CONTROLLER 0xAA +#define PS2_CMD_TEST_PORT_1 0xAB +#define PS2_CMD_DIAGNOSTIC_DUMP 0xAC +#define PS2_CMD_DISABLE_PORT_1 0xAD +#define PS2_CMD_ENABLE_PORT_1 0xAE +#define PS2_CMD_READ_INPUT_PORT 0xC0 +#define PS2_CMD_COPY_INPUT_0_3_TO_4_7_STATUS 0xC1 +#define PS2_CMD_COPY_INPUT_4_7_TO_4_7_STATUS 0xC2 +#define PS2_CMD_READ_OUTPUT_PORT 0xD0 +#define PS2_CMD_WRITE_NEXT_BYTE_TO_OUTPUT_PORT 0xD1 +#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_1_OUTPUT 0xD2 +#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_OUTPUT 0xD3 +#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT 0xD4 +#define PS2_CMD_PULSE_OUTPUT_LINE(n) (0xF0 + n) + +typedef union +{ + struct + { + uint8_t OutputBufferFull : 1; + uint8_t InputBufferFull : 1; + uint8_t SystemFlag : 1; + uint8_t CommandData : 1; + uint8_t Unknown1 : 1; + uint8_t Unknown2 : 1; + uint8_t TimeoutError : 1; + uint8_t ParityError : 1; + }; + uint8_t Raw; +} PS2_STATUSES; + +typedef union +{ + struct + { + uint8_t Port1Interrupt : 1; + uint8_t Port2Interrupt : 1; + uint8_t SystemFlag : 1; + uint8_t Zero0 : 1; + uint8_t Port1Clock : 1; + uint8_t Port2Clock : 1; + uint8_t Port1Translation : 1; + uint8_t Zero1 : 1; + }; + uint8_t Raw; +} PS2_CONFIGURATION; + +typedef union +{ + struct + { + uint8_t SystemReset : 1; + uint8_t A20Gate : 1; + uint8_t Port2Clock : 1; + uint8_t Port2Data : 1; + uint8_t Port1OutputBufferFull : 1; + uint8_t Port2OutputBufferFull : 1; + uint8_t Port1InputBufferFull : 1; + uint8_t Port2InputBufferFull : 1; + }; + uint8_t Raw; +} PS2_OUTPUT_PORT; + +void PIC_EOI(uint8_t IRQ); +void IRQ_MASK(uint8_t IRQ); +void IRQ_UNMASK(uint8_t IRQ); +void PS2Wait(const bool Output); +void PS2WriteCommand(uint8_t Command); +void PS2WriteData(uint8_t Data); +uint8_t PS2ReadData(); +uint8_t PS2ReadStatus(); +uint8_t PS2ReadAfterACK(); +void PS2ClearOutputBuffer(); +int PS2ACKTimeout(); + +#define WaitOutput PS2Wait(DriverID, true) +#define WaitInput PS2Wait(DriverID, false) + + +#define PS2_KBD_CMD_SET_LEDS 0xED +#define PS2_KBD_CMD_ECHO 0xEE +#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0 +#define PS2_KBD_CMD_IDENTIFY 0xF2 +#define PS2_KBD_CMD_TYPEMATIC 0xF3 +#define PS2_KBD_CMD_ENABLE_SCANNING 0xF4 +#define PS2_KBD_CMD_DISABLE_SCANNING 0xF5 +#define PS2_KBD_CMD_DEFAULTS 0xF6 +#define PS2_KBD_CMD_ALL_TYPEMATIC 0xF7 +#define PS2_KBD_CMD_ALL_MAKE_RELEASE 0xF8 +#define PS2_KBD_CMD_ALL_MAKE 0xF9 +#define PS2_KBD_CMD_ALL_TYPEMATIC_MAKE_RELEASE 0xFA +#define PS2_KBD_CMD_SPECIFIC_TYPEMATIC 0xFB +#define PS2_KBD_CMD_SPECIFIC_MAKE_RELEASE 0xFC +#define PS2_KBD_CMD_SPECIFIC_MAKE 0xFD +#define PS2_KBD_CMD_RESEND 0xFE +#define PS2_KBD_CMD_RESET 0xFF + +#define PS2_KBD_RESP_ACK 0xFA +#define PS2_KBD_RESP_ECHO 0xEE +#define PS2_KBD_RESP_RESEND 0xFE +#define PS2_KBD_RESP_TEST_PASSED 0xAA +#define PS2_KBD_RESP_TEST_FAILED 0xFC +#define PS2_KBD_RESP_TEST_FAILED_2 0xFD + +typedef enum +{ + PS2_KBD_LED_SCROLL_LOCK = 1, + PS2_KBD_LED_NUM_LOCK = 2, + PS2_KBD_LED_CAPS_LOCK = 4 +} PS2_KBD_LEDS; + +typedef enum +{ + PS2_KBD_SCAN_CODE_GET_CURRENT = 0, + PS2_KBD_SCAN_CODE_SET_1 = 1, + PS2_KBD_SCAN_CODE_SET_2 = 2, + PS2_KBD_SCAN_CODE_SET_3 = 3, + + PS2_KBD_SC_SET_1 = 0x43, + PS2_KBD_SC_SET_2 = 0x41, + PS2_KBD_SC_SET_3 = 0x3F +} PS2_KBD_SCAN_CODE_SET; + +typedef union +{ + struct + { + /** + * 00000b - 30Hz + * 11111b - 2Hz + */ + uint8_t RepeatRate : 5; + + /** + * 00b - 250ms + * 01b - 500ms + * 10b - 750ms + * 11b - 1000ms + */ + uint8_t Delay : 2; + + /** + * Must be zero + */ + uint8_t Zero : 1; + }; + uint8_t Raw; +} PS2_KBD_TYPEMATIC; + + +#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6 +#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7 +#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8 +#define PS2_MOUSE_CMD_GET_STATUS 0xE9 +#define PS2_MOUSE_CMD_SET_STREAM_MODE 0xEA +#define PS2_MOUSE_CMD_READ_DATA 0xEB +#define PS2_MOUSE_CMD_RESET_WRAP_MODE 0xEC +#define PS2_MOUSE_CMD_SET_WRAP_MODE 0xEE +#define PS2_MOUSE_CMD_SET_REMOTE_MODE 0xF0 +#define PS2_MOUSE_CMD_READ_ID 0xF2 +/** Values: 10, 20, 40, 60, 80, 100, 200 */ +#define PS2_MOUSE_CMD_SET_SAMPLE_RATE 0xF3 +#define PS2_MOUSE_CMD_ENABLE_DATA_REPORTING 0xF4 +#define PS2_MOUSE_CMD_DISABLE_DATA_REPORTING 0xF5 +#define PS2_MOUSE_CMD_SET_DEFAULTS 0xF6 +#define PS2_MOUSE_CMD_RESEND 0xFE +#define PS2_MOUSE_CMD_RESET 0xFF + +#define PS2_MOUSE_RESP_ACK 0xFA +#define PS2_MOUSE_RESP_RESEND 0xFE +#define PS2_MOUSE_RESP_TEST_PASSED 0xAA +#define PS2_MOUSE_RESP_TEST_FAILED 0xFC + +typedef enum +{ + PS2_MOUSE_RES_1 = 0, + PS2_MOUSE_RES_2 = 1, + PS2_MOUSE_RES_4 = 2, + PS2_MOUSE_RES_8 = 3 +} PS2_MOUSE_RESOLUTION; + +typedef struct +{ + union + { + struct + { + uint8_t LeftButton : 1; + uint8_t RightButton : 1; + uint8_t MiddleButton : 1; + uint8_t Always1 : 1; + uint8_t XSign : 1; + uint8_t YSign : 1; + uint8_t XOverflow : 1; + uint8_t YOverflow : 1; + } __attribute__((packed)); + uint8_t Raw; + } Base; + + uint8_t XMovement; + uint8_t YMovement; + + union + { + struct + { + uint8_t Z : 4; + uint8_t Button4 : 1; + uint8_t Button5 : 1; + uint8_t Always0 : 1; + uint8_t Always0_2 : 1; + } __attribute__((packed)); + uint8_t Raw; + } ZMovement; +} PS2_MOUSE_PACKET; + +#endif // !__FENNIX_API_AIP_H__ diff --git a/include/cbuf.hpp b/include/interface/audio.h similarity index 57% rename from include/cbuf.hpp rename to include/interface/audio.h index c81d4597..2c87a131 100644 --- a/include/cbuf.hpp +++ b/include/interface/audio.h @@ -15,31 +15,15 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_CIRCULAR_BUFFER_H__ -#define __FENNIX_KERNEL_CIRCULAR_BUFFER_H__ +#ifndef __FENNIX_API_AUDIO_H__ +#define __FENNIX_API_AUDIO_H__ #include -#include -class CircularBuffer -{ -private: - spin_lock Lock; - uint8_t *Buffer; - size_t BufferSize; - size_t BufferCount; +#if __has_include() +#include +#else +#include +#endif - size_t Head; - size_t Tail; - -public: - CircularBuffer(size_t Size); - ~CircularBuffer(); - size_t Write(const uint8_t *Data, size_t Size); - size_t Read(uint8_t *Data, size_t Size); - size_t Peek(uint8_t *Data, size_t Size); - size_t Count(); - size_t Free(); -}; - -#endif // !__FENNIX_KERNEL_CIRCULAR_BUFFER_H__ +#endif // !__FENNIX_API_AUDIO_H__ diff --git a/include/interface/device.h b/include/interface/device.h new file mode 100644 index 00000000..108aa822 --- /dev/null +++ b/include/interface/device.h @@ -0,0 +1,74 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_API_DEVICE_H__ +#define __FENNIX_API_DEVICE_H__ + +#include + +#ifndef __FENNIX_API_FILESYSTEM_H__ +#if __has_include() +#include +#else +#include +#endif +#endif // !__FENNIX_API_FILESYSTEM_H__ + +typedef enum +{ + DEVICE_TYPE_MASK = 0b1111111100000000000000000000000000000000, + DEVICE_TYPE_NONE = 0b0000000000000000000000000000000000000000, + DEVICE_TYPE_INPUT = 0b0000000100000000000000000000000000000000, + DEVICE_TYPE_AUDIO = 0b0000001000000000000000000000000000000000, + DEVICE_TYPE_NETWORK = 0b0000010000000000000000000000000000000000, + DEVICE_TYPE_BLOCK = 0b0000100000000000000000000000000000000000, + + INPUT_TYPE_NONE = DEVICE_TYPE_INPUT + 0, + INPUT_TYPE_KEYBOARD = DEVICE_TYPE_INPUT + 2, + INPUT_TYPE_MOUSE = DEVICE_TYPE_INPUT + 4, + INPUT_TYPE_JOYSTICK = DEVICE_TYPE_INPUT + 8, + INPUT_TYPE_TOUCHSCREEN = DEVICE_TYPE_INPUT + 16, + INPUT_TYPE_GAMEPAD = DEVICE_TYPE_INPUT + 32, + INPUT_TYPE_ACCELEROMETER = DEVICE_TYPE_INPUT + 64, + INPUT_TYPE_GYROSCOPE = DEVICE_TYPE_INPUT + 128, + INPUT_TYPE_MAGNETOMETER = DEVICE_TYPE_INPUT + 256, + + AUDIO_TYPE_NONE = DEVICE_TYPE_AUDIO + 0, + AUDIO_TYPE_PWM = DEVICE_TYPE_AUDIO + 2, + AUDIO_TYPE_DSP = DEVICE_TYPE_AUDIO + 4, + AUDIO_TYPE_PCM = DEVICE_TYPE_AUDIO + 8, + AUDIO_TYPE_MIDI = DEVICE_TYPE_AUDIO + 16, + + NETWORK_TYPE_NONE = DEVICE_TYPE_NETWORK + 0, + NETWORK_TYPE_ETHERNET = DEVICE_TYPE_NETWORK + 2, + NETWORK_TYPE_WIFI = DEVICE_TYPE_NETWORK + 4, + NETWORK_TYPE_BLUETOOTH = DEVICE_TYPE_NETWORK + 8, + + BLOCK_TYPE_NONE = DEVICE_TYPE_BLOCK + 0, + BLOCK_TYPE_SDCARD = DEVICE_TYPE_BLOCK + 2, + BLOCK_TYPE_HDD = DEVICE_TYPE_BLOCK + 4, + BLOCK_TYPE_SSD = DEVICE_TYPE_BLOCK + 8, + BLOCK_TYPE_USB = DEVICE_TYPE_BLOCK + 16, + BLOCK_TYPE_NVME = DEVICE_TYPE_BLOCK + 32, + BLOCK_TYPE_CDROM = DEVICE_TYPE_BLOCK + 64, + BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128, +} DeviceType; + +EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations); +EXTERNC int UnregisterDevice(dev_t Device); + +#endif // !__FENNIX_API_DEVICE_H__ diff --git a/include/interface/driver.h b/include/interface/driver.h index 0644b210..d51671f0 100644 --- a/include/interface/driver.h +++ b/include/interface/driver.h @@ -20,30 +20,6 @@ #include -typedef enum -{ - _drf_Entry, - _drf_Final, - _drf_Panic, - _drf_Probe, -} __driverRegFunc; - -typedef union -{ - struct - { - uint8_t LeftButton : 1; - uint8_t RightButton : 1; - uint8_t MiddleButton : 1; - uint8_t Button4 : 1; - uint8_t Button5 : 1; - uint8_t Button6 : 1; - uint8_t Button7 : 1; - uint8_t Button8 : 1; - }; - uint8_t Value; -} __MouseButtons; - typedef struct { /* PCIDevice */ void *Device; @@ -55,143 +31,6 @@ typedef struct #define PCI_END 0x0000 #define KEY_NULL 0x00 -typedef enum -{ - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_5, - KEY_6, - KEY_7, - KEY_8, - KEY_9, - KEY_0, - - KEY_Q, - KEY_W, - KEY_E, - KEY_R, - KEY_T, - KEY_Y, - KEY_U, - KEY_I, - KEY_O, - KEY_P, - KEY_A, - KEY_S, - KEY_D, - KEY_F, - KEY_G, - KEY_H, - KEY_J, - KEY_K, - KEY_L, - KEY_Z, - KEY_X, - KEY_C, - KEY_V, - KEY_B, - KEY_N, - KEY_M, - - KEY_F1, - KEY_F2, - KEY_F3, - KEY_F4, - KEY_F5, - KEY_F6, - KEY_F7, - KEY_F8, - KEY_F9, - KEY_F10, - KEY_F11, - KEY_F12, - - KEYPAD_7, - KEYPAD_8, - KEYPAD_9, - KEYPAD_MINUS, - KEYPAD_4, - KEYPAD_5, - KEYPAD_6, - KEYPAD_PLUS, - KEYPAD_1, - KEYPAD_2, - KEYPAD_3, - KEYPAD_0, - KEYPAD_PERIOD, - KEYPAD_RETURN, - KEYPAD_ASTERISK, - KEYPAD_SLASH, - - KEY_LEFT_CTRL, - KEY_RIGHT_CTRL, - KEY_LEFT_SHIFT, - KEY_RIGHT_SHIFT, - KEY_LEFT_ALT, - KEY_RIGHT_ALT, - KEY_ESCAPE, - KEY_MINUS, - KEY_EQUAL, - KEY_BACKSPACE, - KEY_TAB, - KEY_LEFT_BRACKET, - KEY_RIGHT_BRACKET, - KEY_RETURN, - KEY_SEMICOLON, - KEY_APOSTROPHE, - KEY_BACK_TICK, - KEY_BACKSLASH, - KEY_COMMA, - KEY_PERIOD, - KEY_SLASH, - KEY_SPACE, - KEY_CAPS_LOCK, - KEY_NUM_LOCK, - KEY_SCROLL_LOCK, - KEY_PRINT_SCREEN, - - KEY_HOME, - KEY_UP_ARROW, - KEY_LEFT_ARROW, - KEY_RIGHT_ARROW, - KEY_DOWN_ARROW, - KEY_PAGE_UP, - KEY_PAGE_DOWN, - KEY_END, - KEY_INSERT, - KEY_DELETE, - KEY_LEFT_GUI, - KEY_RIGHT_GUI, - KEY_APPS, - - KEY_MULTIMEDIA_PREV_TRACK, - KEY_MULTIMEDIA_NEXT_TRACK, - KEY_MULTIMEDIA_MUTE, - KEY_MULTIMEDIA_CALCULATOR, - KEY_MULTIMEDIA_PLAY, - KEY_MULTIMEDIA_STOP, - KEY_MULTIMEDIA_VOL_DOWN, - KEY_MULTIMEDIA_VOL_UP, - KEY_MULTIMEDIA_WWW_HOME, - KEY_MULTIMEDIA_WWW_SEARCH, - KEY_MULTIMEDIA_WWW_FAVORITES, - KEY_MULTIMEDIA_WWW_REFRESH, - KEY_MULTIMEDIA_WWW_STOP, - KEY_MULTIMEDIA_WWW_FORWARD, - KEY_MULTIMEDIA_WWW_BACK, - KEY_MULTIMEDIA_MY_COMPUTER, - KEY_MULTIMEDIA_EMAIL, - KEY_MULTIMEDIA_MEDIA_SELECT, - - KEY_ACPI_POWER, - KEY_ACPI_SLEEP, - KEY_ACPI_WAKE, - - KEY_PRESSED = 0x80, -} KeyScanCodes; - typedef enum { IOCTL_AUDIO_GET_VOLUME = 0, @@ -221,73 +60,17 @@ typedef enum MAP_CACHE_DISABLE = 1 << 4, } PageMapFlags; -typedef struct +struct __DriverInfo { - struct + const char *Name; + const char *Description; + const char *Author; + struct __DriverVersion { - uint8_t Major; - uint8_t Minor; - uint8_t Patch; - } APIVersion; - - dev_t MajorID; - uintptr_t Base; - - /* Internal */ - int (*RegisterFunction)(dev_t MajorID, void *Function, __driverRegFunc Type); - int (*GetDriverInfo)(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License); - - /* Interrupts */ - int (*RegisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler); - int (*OverrideInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler); - int (*UnregisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler); - int (*UnregisterAllInterruptHandlers)(dev_t MajorID, void *Handler); - - /* /dev/... */ - dev_t (*RegisterDevice)(dev_t MajorID, char Prefix[8], void *Open, void *Close, void *Read, void *Write, void *Ioctl); - int (*UnregisterDevice)(dev_t MajorID, dev_t MinorID); - - /* Logging */ - void (*KPrint)(dev_t MajorID, const char *Format, va_list args); - void (*KernelLog)(dev_t MajorID, const char *Format, va_list args); - - /* Memory */ - void *(*RequestPages)(dev_t MajorID, size_t Pages); - void (*FreePages)(dev_t MajorID, void *Pointer, size_t Pages); - - /* Mapping */ - void (*AppendMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag); - void (*RemoveMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag); - void (*MapPages)(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags); - void (*UnmapPages)(dev_t MajorID, void *VirtualAddress, size_t Pages); - - /* Scheduling */ - pid_t (*CreateKernelProcess)(dev_t MajorID, const char *Name); - pid_t (*CreateKernelThread)(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument); - pid_t (*GetCurrentProcess)(dev_t MajorID); - int (*KillProcess)(dev_t MajorID, pid_t pId, int ExitCode); - int (*KillThread)(dev_t MajorID, pid_t tId, pid_t pId, int ExitCode); - void (*Yield)(dev_t MajorID); - void (*Sleep)(dev_t MajorID, uint64_t Milliseconds); - - /* PCI */ - __PCIArray *(*GetPCIDevices)(dev_t MajorID, uint16_t Vendors[], uint16_t Devices[]); - void (*InitializePCI)(dev_t MajorID, void *Header); - uint32_t (*GetBAR)(dev_t MajorID, uint8_t Index, void *Header); - - /* Kernel std API */ - void *(*memcpy)(dev_t MajorID, void *Destination, const void *Source, size_t Length); - void *(*memset)(dev_t MajorID, void *Destination, int Value, size_t Length); - void *(*memmove)(dev_t MajorID, void *Destination, const void *Source, size_t Length); - int (*memcmp)(dev_t MajorID, const void *Left, const void *Right, size_t Length); - size_t (*strlen)(dev_t MajorID, const char *String); - char *(*strcpy)(dev_t MajorID, char *Destination, const char *Source); - char *(*strcat)(dev_t MajorID, char *Destination, const char *Source); - int (*strcmp)(dev_t MajorID, const char *Left, const char *Right); - int (*strncmp)(dev_t MajorID, const char *Left, const char *Right, size_t Length); - char *(*strchr)(dev_t MajorID, const char *String, int Character); - char *(*strrchr)(dev_t MajorID, const char *String, int Character); - char *(*strstr)(dev_t MajorID, const char *Haystack, const char *Needle); -} __driverAPI; + int APIVersion; + int Major, Minor, Patch; + } Version; + const char *License; +}; #endif // !__FENNIX_API_DRIVER_FUNCTIONS_H__ diff --git a/include/interface/fs.h b/include/interface/fs.h index 8ddc2424..374cc539 100644 --- a/include/interface/fs.h +++ b/include/interface/fs.h @@ -18,9 +18,7 @@ #ifndef __FENNIX_API_FILESYSTEM_H__ #define __FENNIX_API_FILESYSTEM_H__ -#ifdef __kernel__ #include -#endif #define SEEK_SET 0 #define SEEK_CUR 1 @@ -253,30 +251,6 @@ struct kdirent char d_name[]; }; -struct InodeOperations -{ - int (*Lookup)(struct Inode *Parent, const char *Name, struct Inode **Result); - int (*Create)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result); - int (*Remove)(struct Inode *Parent, const char *Name); - int (*Rename)(struct Inode *Parent, const char *OldName, const char *NewName); - ssize_t (*Read)(struct Inode *Node, void *Buffer, size_t Size, off_t Offset); - ssize_t (*Write)(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset); - int (*Truncate)(struct Inode *Node, off_t Size); - int (*Open)(struct Inode *Node, int Flags, mode_t Mode); - int (*Close)(struct Inode *Node); - int (*Ioctl)(struct Inode *Node, unsigned long Request, void *Argp); - ssize_t (*ReadDir)(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries); - int (*MkDir)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result); - int (*RmDir)(struct Inode *Parent, const char *Name); - int (*SymLink)(struct Inode *Parent, const char *Name, const char *Target, struct Inode **Result); - ssize_t (*ReadLink)(struct Inode *Node, char *Buffer, size_t Size); - off_t (*Seek)(struct Inode *Node, off_t Offset); - int (*Stat)(struct Inode *Node, struct kstat *Stat); -} __attribute__((packed)); - -#define I_FLAG_MOUNTPOINT 0x1 -#define I_FLAG_CACHE_KEEP 0x2 - struct Inode { dev_t Device, RawDevice; @@ -335,6 +309,32 @@ struct Inode #endif // __cplusplus }; +struct InodeOperations +{ + int (*Lookup)(struct Inode *Parent, const char *Name, struct Inode **Result); + int (*Create)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result); + int (*Remove)(struct Inode *Parent, const char *Name); + int (*Rename)(struct Inode *Parent, const char *OldName, const char *NewName); + ssize_t (*Read)(struct Inode *Node, void *Buffer, size_t Size, off_t Offset); + ssize_t (*Write)(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset); + int (*Truncate)(struct Inode *Node, off_t Size); + int (*Open)(struct Inode *Node, int Flags, mode_t Mode); + int (*Close)(struct Inode *Node); + int (*Ioctl)(struct Inode *Node, unsigned long Request, void *Argp); + ssize_t (*ReadDir)(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries); + int (*MkDir)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result); + int (*RmDir)(struct Inode *Parent, const char *Name); + int (*SymLink)(struct Inode *Parent, const char *Name, const char *Target, struct Inode **Result); + ssize_t (*ReadLink)(struct Inode *Node, char *Buffer, size_t Size); + off_t (*Seek)(struct Inode *Node, off_t Offset); + int (*Stat)(struct Inode *Node, struct kstat *Stat); +} __attribute__((packed)); + +#define I_FLAG_ROOT 0x1 +#define I_FLAG_MOUNTPOINT 0x2 +#define I_FLAG_CACHE_KEEP 0x4 + +struct FileSystemInfo; struct SuperBlockOperations { int (*AllocateInode)(struct FileSystemInfo *Info, struct Inode **Result); @@ -360,12 +360,13 @@ struct SuperBlockOperations * * @return Zero on success, otherwise an error code. */ - int (*Destroy)(FileSystemInfo *Info); + int (*Destroy)(struct FileSystemInfo *Info); } __attribute__((packed)); struct FileSystemInfo { const char *Name; + const char *RootName; int Flags; struct SuperBlockOperations SuperOps; struct InodeOperations Ops; @@ -373,7 +374,7 @@ struct FileSystemInfo void *PrivateData; } __attribute__((packed)); -dev_t RegisterFileSystem(FileSystemInfo *Info, struct Inode *Root); +dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root); int UnregisterFileSystem(dev_t Device); #endif // !__FENNIX_API_FILESYSTEM_H__ diff --git a/include/interface/input.h b/include/interface/input.h new file mode 100644 index 00000000..6e124bf7 --- /dev/null +++ b/include/interface/input.h @@ -0,0 +1,234 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_API_INPUT_H__ +#define __FENNIX_API_INPUT_H__ + +#include + +#if __has_include() +#include +#else +#include +#endif + +struct InodeOperations; + +typedef enum +{ + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_A, + KEY_S, + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, + KEY_N, + KEY_M, + + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + + KEYPAD_7, + KEYPAD_8, + KEYPAD_9, + KEYPAD_MINUS, + KEYPAD_4, + KEYPAD_5, + KEYPAD_6, + KEYPAD_PLUS, + KEYPAD_1, + KEYPAD_2, + KEYPAD_3, + KEYPAD_0, + KEYPAD_PERIOD, + KEYPAD_RETURN, + KEYPAD_ASTERISK, + KEYPAD_SLASH, + + KEY_LEFT_CTRL, + KEY_RIGHT_CTRL, + KEY_LEFT_SHIFT, + KEY_RIGHT_SHIFT, + KEY_LEFT_ALT, + KEY_RIGHT_ALT, + KEY_ESCAPE, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSPACE, + KEY_TAB, + KEY_LEFT_BRACKET, + KEY_RIGHT_BRACKET, + KEY_RETURN, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_BACK_TICK, + KEY_BACKSLASH, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_SPACE, + KEY_CAPS_LOCK, + KEY_NUM_LOCK, + KEY_SCROLL_LOCK, + KEY_PRINT_SCREEN, + + KEY_HOME, + KEY_UP_ARROW, + KEY_LEFT_ARROW, + KEY_RIGHT_ARROW, + KEY_DOWN_ARROW, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_END, + KEY_INSERT, + KEY_DELETE, + KEY_LEFT_GUI, + KEY_RIGHT_GUI, + KEY_APPS, + + KEY_MULTIMEDIA_PREV_TRACK, + KEY_MULTIMEDIA_NEXT_TRACK, + KEY_MULTIMEDIA_MUTE, + KEY_MULTIMEDIA_CALCULATOR, + KEY_MULTIMEDIA_PLAY, + KEY_MULTIMEDIA_STOP, + KEY_MULTIMEDIA_VOL_DOWN, + KEY_MULTIMEDIA_VOL_UP, + KEY_MULTIMEDIA_WWW_HOME, + KEY_MULTIMEDIA_WWW_SEARCH, + KEY_MULTIMEDIA_WWW_FAVORITES, + KEY_MULTIMEDIA_WWW_REFRESH, + KEY_MULTIMEDIA_WWW_STOP, + KEY_MULTIMEDIA_WWW_FORWARD, + KEY_MULTIMEDIA_WWW_BACK, + KEY_MULTIMEDIA_MY_COMPUTER, + KEY_MULTIMEDIA_EMAIL, + KEY_MULTIMEDIA_MEDIA_SELECT, + + KEY_ACPI_POWER, + KEY_ACPI_SLEEP, + KEY_ACPI_WAKE, + + KEY_PRESSED = 0x80, +} KeyScanCodes; + +typedef struct +{ + KeyScanCodes Key; +} KeyboardReport; + +typedef struct +{ + long X, Y; + int8_t Z; + uint8_t Absolute : 1; + uint8_t LeftButton : 1; + uint8_t RightButton : 1; + uint8_t MiddleButton : 1; + uint8_t Button4 : 1; + uint8_t Button5 : 1; + uint8_t Button6 : 1; + uint8_t Button7 : 1; + uint8_t Button8 : 1; +} MouseReport; + +typedef struct +{ +} JoystickReport; + +typedef struct +{ + uint16_t X, Y; + uint8_t Pressure; +} TouchScreenReport; + +typedef struct +{ +} GamepadReport; + +typedef struct +{ +} AccelerometerReport; + +typedef struct +{ +} GyroscopeReport; + +typedef struct +{ +} MagnetometerReport; + +typedef struct +{ + DeviceType Type; + dev_t Device; + union + { + KeyboardReport Keyboard; + MouseReport Mouse; + JoystickReport Joystick; + TouchScreenReport TouchScreen; + GamepadReport Gamepad; + AccelerometerReport Accelerometer; + GyroscopeReport Gyroscope; + MagnetometerReport Magnetometer; + /* ... */ + }; +} InputReport; + +EXTERNC int ReportInputEvent(InputReport *Report); + +#endif // !__FENNIX_API_INPUT_H__ diff --git a/include/interface/network.h b/include/interface/network.h new file mode 100644 index 00000000..89f7bb10 --- /dev/null +++ b/include/interface/network.h @@ -0,0 +1,29 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_API_NETWORK_H__ +#define __FENNIX_API_NETWORK_H__ + +#include + +#if __has_include() +#include +#else +#include +#endif + +#endif // !__FENNIX_API_NETWORK_H__ diff --git a/include/interface/pci.h b/include/interface/pci.h new file mode 100644 index 00000000..cd96b6a6 --- /dev/null +++ b/include/interface/pci.h @@ -0,0 +1,184 @@ +/* + This file is part of Fennix Drivers. + + Fennix Drivers is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Drivers is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Drivers. If not, see . +*/ + +#ifndef __FENNIX_API_PCI_H__ +#define __FENNIX_API_PCI_H__ + +#include + +/* https://sites.uclouvain.be/SystInfo/usr/include/linux/pci_regs.h.html */ +typedef enum +{ + /** @brief Enable response in I/O space */ + PCI_COMMAND_IO = 0x1, + /** @brief Enable response in Memory space */ + PCI_COMMAND_MEMORY = 0x2, + /** @brief Enable bus mastering */ + PCI_COMMAND_MASTER = 0x4, + /** @brief Enable response to special cycles */ + PCI_COMMAND_SPECIAL = 0x8, + /** @brief Use memory write and invalidate */ + PCI_COMMAND_INVALIDATE = 0x10, + /** @brief Enable palette snooping */ + PCI_COMMAND_VGA_PALETTE = 0x20, + /** @brief Enable parity checking */ + PCI_COMMAND_PARITY = 0x40, + /** @brief Enable address/data stepping */ + PCI_COMMAND_WAIT = 0x80, + /** @brief Enable SERR */ + PCI_COMMAND_SERR = 0x100, + /** @brief Enable back-to-back writes */ + PCI_COMMAND_FAST_BACK = 0x200, + /** @brief INTx Emulation Disable */ + PCI_COMMAND_INTX_DISABLE = 0x400 +} PCI_COMMANDS; + +typedef struct +{ + uint16_t VendorID; + uint16_t DeviceID; + uint16_t Command; + uint16_t Status; + uint8_t RevisionID; + uint8_t ProgIF; + uint8_t Subclass; + uint8_t Class; + uint8_t CacheLineSize; + uint8_t LatencyTimer; + uint8_t HeaderType; + uint8_t BIST; +} __attribute__((packed)) PCIDeviceHeader; + +typedef struct +{ + PCIDeviceHeader Header; + uint32_t BAR0; + uint32_t BAR1; + uint32_t BAR2; + uint32_t BAR3; + uint32_t BAR4; + uint32_t BAR5; + uint32_t CardbusCISPointer; + uint16_t SubsystemVendorID; + uint16_t SubsystemID; + uint32_t ExpansionROMBaseAddress; + uint8_t CapabilitiesPointer; + uint8_t Reserved0; + uint16_t Reserved1; + uint32_t Reserved2; + uint8_t InterruptLine; + uint8_t InterruptPin; + uint8_t MinGrant; + uint8_t MaxLatency; +} __attribute__((packed)) PCIHeader0; + +typedef struct +{ + PCIDeviceHeader Header; + uint32_t BAR0; + uint32_t BAR1; + uint8_t PrimaryBusNumber; + uint8_t SecondaryBusNumber; + uint8_t SubordinateBusNumber; + uint8_t SecondaryLatencyTimer; + uint8_t IOBase; + uint8_t IOLimit; + uint16_t SecondaryStatus; + uint16_t MemoryBase; + uint16_t MemoryLimit; + uint16_t PrefetchableMemoryBase; + uint16_t PrefetchableMemoryLimit; + uint32_t PrefetchableMemoryBaseUpper32; + uint32_t PrefetchableMemoryLimitUpper32; + uint16_t IOBaseUpper16; + uint16_t IOLimitUpper16; + uint8_t CapabilitiesPointer; + uint8_t Reserved0; + uint16_t Reserved1; + uint32_t ExpansionROMBaseAddress; + uint8_t InterruptLine; + uint8_t InterruptPin; + uint16_t BridgeControl; +} __attribute__((packed)) PCIHeader1; + +typedef struct +{ + PCIDeviceHeader Header; + uint32_t CardbusSocketRegistersBaseAddress; + uint8_t CapabilitiesPointer; + uint8_t Reserved0; + uint16_t SecondaryStatus; + uint8_t PCIbusNumber; + uint8_t CardbusBusNumber; + uint8_t SubordinateBusNumber; + uint8_t CardbusLatencyTimer; + uint32_t MemoryBase0; + uint32_t MemoryLimit0; + uint32_t MemoryBase1; + uint32_t MemoryLimit1; + uint32_t IOBase0; + uint32_t IOLimit0; + uint32_t IOBase1; + uint32_t IOLimit1; + uint8_t InterruptLine; + uint8_t InterruptPin; + uint16_t BridgeControl; + uint16_t SubsystemVendorID; + uint16_t SubsystemID; + uint32_t LegacyBaseAddress; +} __attribute__((packed)) PCIHeader2; + +typedef struct +{ + uint64_t BaseAddress; + uint16_t PCISegGroup; + uint8_t StartBus; + uint8_t EndBus; + uint32_t Reserved; +} __attribute__((packed)) DeviceConfig; + +typedef struct +{ + PCIDeviceHeader *Header; + DeviceConfig *Config; + uint32_t Bus; + uint32_t Device; + uint32_t Function; +} __attribute__((packed)) PCIDevice; + +typedef struct +{ + PCIDevice *Device; + /* PCIArray */ void *Next; +} __attribute__((packed)) PCIArray; + +#ifdef __cplusplus +extern "C" +{ +#endif + + PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]); + void InitializePCI(PCIDevice *Device); + uint32_t GetBAR(uint8_t Index, PCIDevice *Device); + uint8_t iLine(PCIDevice *Device); + uint8_t iPin(PCIDevice *Device); + +#ifdef __cplusplus +} +#endif + +#endif // !__FENNIX_API_PCI_H__ diff --git a/include/ring.hpp b/include/ring.hpp new file mode 100644 index 00000000..8c0bf693 --- /dev/null +++ b/include/ring.hpp @@ -0,0 +1,124 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_RING_BUFFER_H__ +#define __FENNIX_KERNEL_RING_BUFFER_H__ + +#include +#include + +template +class RingBuffer +{ +private: + spin_lock *Lock; + T *Buffer; + size_t BufferSize; + size_t BufferCount; + + size_t Head; + size_t Tail; + +public: + RingBuffer(size_t Size = 16) + : Lock(new spin_lock()), + Buffer(new T[Size]), + BufferSize(Size), + BufferCount(0), + Head(0), + Tail(0) {} + + ~RingBuffer() + { + delete Lock; + delete[] Buffer; + } + + size_t Write(const T *Data, size_t Size) + { + sl_guard(*Lock); + + size_t written = 0; + while (Size > 0) + { + if (BufferCount == BufferSize) + break; + + Buffer[Head] = *Data++; + Head = (Head + 1) % BufferSize; + BufferCount++; + written++; + Size--; + } + + return written; + } + + size_t Read(T *Data, size_t Size) + { + sl_guard(*Lock); + + size_t read = 0; + while (Size > 0) + { + if (BufferCount == 0) + break; + + *Data++ = Buffer[Tail]; + Tail = (Tail + 1) % BufferSize; + BufferCount--; + read++; + Size--; + } + + return read; + } + + size_t Peek(T *Data, size_t Size) + { + sl_guard(*Lock); + + size_t read = 0; + size_t tail = Tail; + while (Size > 0) + { + if (BufferCount == 0) + break; + + *Data++ = Buffer[tail]; + tail = (tail + 1) % BufferSize; + read++; + Size--; + } + + return read; + } + + size_t Count() + { + sl_guard(*Lock); + return BufferCount; + } + + size_t Free() + { + sl_guard(*Lock); + return BufferSize - BufferCount; + } +}; + +#endif // !__FENNIX_KERNEL_RING_BUFFER_H__ diff --git a/include/types.h b/include/types.h index 2be25afd..d8e8ce6b 100644 --- a/include/types.h +++ b/include/types.h @@ -95,52 +95,6 @@ typedef __builtin_va_list va_list; #define VPOKE(type, address) (*((volatile type *)(address))) #define POKE(type, address) (*((type *)(address))) -#ifndef __cplusplus - -#ifdef __STDC__ -#ifdef __STDC_VERSION__ -#if (__STDC_VERSION__ >= 201710L) -#define C_LANGUAGE_STANDARD 2018 -#elif (__STDC_VERSION__ >= 201112L) -#define C_LANGUAGE_STANDARD 2011 -#elif (__STDC_VERSION__ >= 199901L) -#define C_LANGUAGE_STANDARD 1999 -#elif (__STDC_VERSION__ >= 199409L) -#define C_LANGUAGE_STANDARD 1995 -#endif -#else -#define C_LANGUAGE_STANDARD 1990 -#endif -#else -#define C_LANGUAGE_STANDARD 1972 -#endif - -#else - -#ifdef __STDC__ -#ifdef __cplusplus -#if (__cplusplus >= 202100L) -#define CPP_LANGUAGE_STANDARD 2023 -#elif (__cplusplus >= 202002L) -#define CPP_LANGUAGE_STANDARD 2020 -#elif (__cplusplus >= 201703L) -#define CPP_LANGUAGE_STANDARD 2017 -#elif (__cplusplus >= 201402L) -#define CPP_LANGUAGE_STANDARD 2014 -#elif (__cplusplus >= 201103L) -#define CPP_LANGUAGE_STANDARD 2011 -#elif (__cplusplus >= 199711L) -#define CPP_LANGUAGE_STANDARD 1998 -#endif -#else -#define CPP_LANGUAGE_STANDARD __cplusplus -#endif -#else -#define CPP_LANGUAGE_STANDARD __cplusplus -#endif - -#endif // __cplusplus - #ifndef __SIG_ATOMIC_TYPE__ #define __SIG_ATOMIC_TYPE__ int #endif @@ -511,11 +465,22 @@ typedef uint48_t uint_fast48_t; #define StackPop(stack, type) \ *((type *)stack++) -#define ReturnLogError(ret, Format, ...) \ +#define ReturnLogError(ret, format, ...) \ { \ - trace(Format, ##__VA_ARGS__); \ + trace(format, ##__VA_ARGS__); \ return ret; \ } \ - while (0) + while (0) \ + __builtin_unreachable() + +#define AssertReturnError(condition, ret) \ + do \ + { \ + if (__builtin_expect(!!(!(condition)), 0)) \ + { \ + error("\"%s\" failed!", #condition); \ + return ret; \ + } \ + } while (0) #endif // !__FENNIX_KERNEL_TYPES_H__ diff --git a/kernel_thread.cpp b/kernel_thread.cpp index 672a97db..96717927 100644 --- a/kernel_thread.cpp +++ b/kernel_thread.cpp @@ -66,15 +66,18 @@ void KernelMainThread() TreeFS(fs->GetRoot(0), 0); #endif - KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", - __DATE__, __TIME__, CPP_LANGUAGE_STANDARD); - KPrint("C++ Language Version (__cplusplus): %ld", __cplusplus); + KPrint("Kernel compiled using GCC %d.%d.%d as of %s %s with Standard C++ %dL", + __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, + __DATE__, __TIME__, + __cplusplus); if (IsVirtualizedEnvironment()) KPrint("Running in a virtualized environment"); KPrint("Initializing Driver Manager"); DriverManager = new Driver::Manager; + TaskManager->CreateThread(thisProcess, Tasking::IP(Driver::ManagerDaemonWrapper)) + ->Rename("Device Service"); KPrint("Loading Drivers"); DriverManager->PreloadDrivers(); @@ -88,8 +91,8 @@ void KernelMainThread() KPrint("Executing %s", Config.InitPath); int ExitCode = -1; - Tasking::TCB *initThread; Tasking::PCB *initProc; + Tasking::TCB *initThread; int tid = SpawnInit(); if (tid < 0) { diff --git a/kshell/commands/cat.cpp b/kshell/commands/cat.cpp index 3f88c470..9f18556c 100644 --- a/kshell/commands/cat.cpp +++ b/kshell/commands/cat.cpp @@ -28,29 +28,34 @@ void cmd_cat(const char *args) if (args[0] == '\0') return; - /* FIXME: Reimplement this later */ - assert(!"Function not implemented"); - // Node *thisNode = fs->GetByPath(args, thisProcess->CWD, true); - // if (thisNode == nullptr) - // { - // printf("cat: %s: No such file or directory\n", args); - // return; - // } + FileNode *node = fs->GetByPath(args, nullptr); - // if (!thisNode->Stat.IsType(FILE) && !thisNode->Stat.IsType(CHARDEVICE)) - // { - // printf("cat: %s: Not a file\n", args); - // return; - // } + if (node == nullptr) + { + printf("cat: %s: No such file or directory\n", args); + return; + } - // vfs::FileHandle *fd = fs->Open(thisNode->FilePath, nullptr, true); + if (!node->IsRegularFile() && !node->IsCharacterDevice()) + { + printf("cat: %s: Not a regular file or character device\n", args); + return; + } - // uint8_t *buffer = new uint8_t[fd->node->Stat.Size + 1]; - // ssize_t rBytes = fd->read(buffer, fd->node->Stat.Size); - // if (rBytes > 0) - // printf("%s\n", buffer); - // else - // printf("cat: %s: Could not read file\n", args); - // delete[] buffer; - // delete fd; + if (node->IsCharacterDevice()) + { + printf("cat: %s: Character devices are not supported yet\n", args); + return; + } + + kstat stat = {}; + node->Stat(&stat); + + uint8_t *buffer = new uint8_t[stat.Size + 1]; + ssize_t rBytes = node->Read(buffer, stat.Size, 0); + if (rBytes > 0) + printf("%s\n", buffer); + else + printf("cat: %s: Could not read file\n", args); + delete[] buffer; } diff --git a/kshell/commands/cd.cpp b/kshell/commands/cd.cpp index 9b562973..64f2a508 100644 --- a/kshell/commands/cd.cpp +++ b/kshell/commands/cd.cpp @@ -28,24 +28,19 @@ void cmd_cd(const char *args) if (args[0] == '\0') return; - /* FIXME: Reimplement this later */ - assert(!"Function not implemented"); - // Node *thisNode = fs->GetByPath(args, thisProcess->CWD, true); + FileNode *node = fs->GetByPath(args, nullptr); - // if (thisNode == nullptr) - // { - // printf("cd: %s: No such file or directory\n", args); - // return; - // } + if (node == nullptr) + { + printf("cd: %s: No such file or directory\n", args); + return; + } - // if (thisNode->Stat.IsType(SYMLINK)) - // thisNode = fs->GetByPath(thisNode->GetSymLink(), nullptr, true); + if (!node->IsDirectory()) + { + printf("cd: %s: Not a directory\n", args); + return; + } - // if (!thisNode->Stat.IsType(DIRECTORY)) - // { - // printf("cd: %s: Not a directory\n", args); - // return; - // } - - // thisProcess->CWD = thisNode; + thisProcess->CWD = node; } diff --git a/kshell/commands/ls.cpp b/kshell/commands/ls.cpp index e11e5ffc..baf26c4e 100644 --- a/kshell/commands/ls.cpp +++ b/kshell/commands/ls.cpp @@ -23,84 +23,113 @@ using namespace vfs; -// const char *ColorNodeType(Node *node) -// { -// switch (node->Stat.GetFileType()) -// { -// case DIRECTORY: -// return "\e3871F5"; -// case BLOCKDEVICE: -// return "\eE8CD1E"; -// case CHARDEVICE: -// return "\e86E01F"; -// case PIPE: -// return "\eE0991F"; -// case SYMLINK: -// return "\e1FB9E0"; -// case FILE: -// return "\eCCCCCC"; -// default: -// return "\eF72020"; -// } -// } +const char *ColorNodeType(FileNode *node) +{ + if (node->IsRegularFile()) + return "\eCCCCCC"; + else if (node->IsDirectory()) + return "\e3871F5"; + else if (node->IsBlockDevice()) + return "\eE8CD1E"; + else if (node->IsCharacterDevice()) + return "\e86E01F"; + else if (node->IsFIFO()) + return "\eE0991F"; + else if (node->IsSymbolicLink()) + return "\e1FB9E0"; + else + return "\eF72020"; +} -// size_t MaxNameLength(Node *nodes) -// { -// size_t maxLength = 0; -// foreach (auto &node in nodes->GetChildren(true)) -// maxLength = std::max(maxLength, strlen(node->FileName)); -// return maxLength; -// } +__no_sanitize("alignment") size_t MaxNameLength(FileNode *nodes) +{ + size_t maxLength = 0; -// void PrintLS(Node *node) -// { -// size_t maxNameLength = MaxNameLength(node); -// int count = 0; -// bool first = true; -// foreach (auto &var in node->GetChildren(true)) -// { -// if (count % 5 == 0 && !first) -// printf("\n"); -// printf(" %s%-*s ", ColorNodeType(var), (int)maxNameLength, var->FileName); -// count++; -// first = false; -// } -// printf("\eCCCCCC\n"); -// } + kdirent *dirBuffer = new kdirent[16]; + ssize_t read = 0; + off_t offset = 0; + while ((read = nodes->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0) + { + if (read / sizeof(kdirent) == 0) + break; + + off_t bufOffset = 0; + debug("There are %ld entries in this directory", read / sizeof(kdirent)); + for (size_t i = 0; i < read / sizeof(kdirent); i++) + { + kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset); + if (dirent->d_reclen == 0) + break; + bufOffset += dirent->d_reclen; + maxLength = std::max(maxLength, strlen(dirent->d_name)); + debug("dirent->d_name: %s (max length: %ld)", dirent->d_name, maxLength); + } + offset += read / sizeof(kdirent); + } + delete[] dirBuffer; + return maxLength; +} + +__no_sanitize("alignment") void PrintLS(FileNode *node) +{ + size_t maxNameLength = MaxNameLength(node); + int count = 0; + bool first = true; + + kdirent *dirBuffer = new kdirent[16]; + ssize_t read = 0; + off_t offset = 0; + while ((read = node->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0) + { + if (read / sizeof(kdirent) == 0) + break; + + off_t bufOffset = 0; + for (size_t i = 0; i < read / sizeof(kdirent); i++) + { + if (count % 5 == 0 && !first) + printf("\n"); + kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset); + if (dirent->d_reclen == 0) + break; + bufOffset += dirent->d_reclen; + printf(" %s%-*s ", ColorNodeType(node), (int)maxNameLength, dirent->d_name); + count++; + first = false; + } + offset += read / sizeof(kdirent); + } + + printf("\eCCCCCC\n"); + delete[] dirBuffer; +} void cmd_ls(const char *args) { - /* FIXME: Reimplement this later */ - assert(!"Function not implemented"); + if (args[0] == '\0') + { + FileNode *rootNode = thisProcess->CWD; - // if (args[0] == '\0') - // { - // Node *rootNode = thisProcess->CWD; + if (rootNode == nullptr) + rootNode = fs->GetRoot(0); - // if (rootNode == nullptr) - // rootNode = fs->FileSystemRoots->GetChildren(true)[0]; + PrintLS(rootNode); + return; + } - // PrintLS(rootNode); - // } - // else - // { - // Node *thisNode = fs->GetByPath(args, thisProcess->CWD, true); + FileNode *thisNode = fs->GetByPath(args, nullptr); - // if (thisNode == nullptr) - // { - // printf("ls: %s: No such file or directory\n", args); - // return; - // } + if (thisNode == nullptr) + { + printf("ls: %s: No such file or directory\n", args); + return; + } - // if (thisNode->Stat.IsType(SYMLINK)) - // thisNode = fs->GetByPath(thisNode->GetSymLink(), nullptr, true); + if (!thisNode->IsDirectory()) + { + printf("%s%s\n", ColorNodeType(thisNode), thisNode->Path.c_str()); + return; + } - // if (!thisNode->Stat.IsType(DIRECTORY)) - // { - // printf("%s%s\n", ColorNodeType(thisNode), thisNode->FileName); - // return; - // } - - // PrintLS(thisNode); - // } + PrintLS(thisNode); } diff --git a/kshell/commands/modinfo.cpp b/kshell/commands/modinfo.cpp index 87cb719a..21973893 100644 --- a/kshell/commands/modinfo.cpp +++ b/kshell/commands/modinfo.cpp @@ -53,11 +53,16 @@ void cmd_modinfo(const char *args) } Driver::DriverObject drv = drivers[id]; + + char drvVersion[32]; + snprintf(drvVersion, sizeof(drvVersion), "%d.%d.%d", + drv.Version.Major, drv.Version.Minor, drv.Version.Patch); + printf("Base Info:\n"); printf(" Name: %s\n", drv.Name); printf(" Description: %s\n", drv.Description); printf(" Author: %s\n", drv.Author); - printf(" Version: %s\n", drv.Version); + printf(" Version: %s\n", drvVersion); printf(" License: %s\n", drv.License); printf("Resource Info:\n"); printf(" Initialized: %s\n", drv.Initialized ? "yes" : "no"); diff --git a/kshell/commands/tree.cpp b/kshell/commands/tree.cpp index aa031fc1..09a660fa 100644 --- a/kshell/commands/tree.cpp +++ b/kshell/commands/tree.cpp @@ -21,57 +21,81 @@ #include "../../kernel.h" -using namespace vfs; +void tree_loop(FileNode *rootNode, int depth = 0) +{ + // foreach (auto Child in rootNode->GetChildren(true)) + // { + // Display->UpdateBuffer(); + // if (Child->Stat.IsType(DIRECTORY) || Child->Stat.IsType(MOUNTPOINT)) + // { + // printf("%*s%*s%*s|- %s\n", + // depth, "", + // depth, "", + // depth, "", + // Child->FileName); + // tree_loop(Child, depth + 1); + // } + // else + // printf("%*s%*s%*s|- %s\n", + // depth, "", + // depth, "", + // depth, "", + // Child->FileName); + // } -// void tree_loop(Node *rootNode, int depth = 0) -// { -// foreach (auto Child in rootNode->GetChildren(true)) -// { -// Display->UpdateBuffer(); -// if (Child->Stat.IsType(DIRECTORY) || Child->Stat.IsType(MOUNTPOINT)) -// { -// printf("%*s%*s%*s|- %s\n", -// depth, "", -// depth, "", -// depth, "", -// Child->FileName); -// tree_loop(Child, depth + 1); -// } -// else -// printf("%*s%*s%*s|- %s\n", -// depth, "", -// depth, "", -// depth, "", -// Child->FileName); -// } -// } + kdirent *dirBuffer = new kdirent[16]; + ssize_t read = 0; + off_t offset = 0; + while ((read = rootNode->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0) + { + if (read / sizeof(kdirent) == 0) + break; + + off_t bufOffset = 0; + for (size_t i = 0; i < read / sizeof(kdirent); i++) + { + kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset); + if (dirent->d_reclen == 0) + break; + bufOffset += dirent->d_reclen; + + if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; + + FileNode *node = fs->GetByPath(dirent->d_name, rootNode); + if (node == nullptr) + continue; + + for (int i = 0; i < depth; i++) + printf(" "); + printf("|- %s\n", dirent->d_name); + + if (node->IsDirectory()) + tree_loop(node, depth + 1); + } + offset += read; + } + delete[] dirBuffer; +} void cmd_tree(const char *args) { - /* FIXME: Reimplement this later */ - assert(!"Function not implemented"); + FileNode *rootNode = thisProcess->CWD; + if (args[0] == '\0') + { + if (rootNode == nullptr) + rootNode = fs->GetRoot(0); + } + else + { + rootNode = fs->GetByPath(args, nullptr); + if (rootNode == nullptr) + { + printf("ls: %s: No such file or directory\n", args); + return; + } + } - // Node *rootNode = thisProcess->CWD; - // if (args[0] == '\0') - // { - // if (rootNode == nullptr) - // rootNode = fs->FileSystemRoots->GetChildren(true)[0]; - // } - // else - // { - // rootNode = fs->GetByPath(args, thisProcess->CWD, true); - // if (rootNode == nullptr) - // { - // printf("ls: %s: No such file or directory\n", args); - // return; - // } - // if (!rootNode->Stat.IsType(DIRECTORY)) - // { - // printf("%s\n", rootNode->FileName); - // return; - // } - // } - - // printf("%s\n", rootNode->FileName); - // tree_loop(rootNode); + printf("%s\n", rootNode->Name.c_str()); + tree_loop(rootNode); } diff --git a/kshell/shell.cpp b/kshell/shell.cpp index c6b26888..1942c80c 100644 --- a/kshell/shell.cpp +++ b/kshell/shell.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -160,14 +161,14 @@ void StartKernelShell() KPrint("Starting kernel shell..."); thisThread->SetPriority(Tasking::TaskPriority::High); - std::string strBuf; + std::string strBuf = ""; std::vector history; size_t hIdx = 0; bool ctrlDown = false; bool upperCase = false; bool tabDblPress = false; - FileNode *kfd = fs->GetByPath("/dev/key", nullptr); + FileNode *kfd = fs->GetByPath("/dev/input/keyboard", fs->GetRoot(0)); if (kfd == nullptr) { KPrint("Failed to open keyboard device!"); @@ -194,18 +195,17 @@ void StartKernelShell() FileNode *cwd = thisProcess->CWD; if (!cwd) - cwd = fs->GetByPath("/", nullptr); + cwd = fs->GetRoot(0); + std::string cwdStr = fs->GetByNode(cwd); printf("\e34C6EB%s@%s:%s$ \eCCCCCC", - "kernel", - "fennix", - cwd->Path.c_str()); + "kernel", "fennix", + cwdStr.c_str()); Display->UpdateBuffer(); Display->GetBufferCursor(&homeX, &homeY); - uint8_t scBuf[2]; - scBuf[1] = 0x00; /* Request scan code */ + KeyboardReport scBuf{}; ssize_t nBytes; while (true) { @@ -215,24 +215,21 @@ void StartKernelShell() CurY.store(__cy); CurHalt.store(false); - nBytes = kfd->Read(scBuf, 2, 0); + nBytes = kfd->Read(&scBuf, sizeof(KeyboardReport), 0); if (nBytes == 0) continue; - if (nBytes < 0) + if (nBytes < (ssize_t)sizeof(KeyboardReport)) { KPrint("Failed to read from keyboard device: %s", strerror((int)nBytes)); return; } - if (scBuf[0] == 0x00) - continue; - BlinkerSleep.store(TimeManager->CalculateTarget(250, Time::Units::Milliseconds)); CurHalt.store(true); UpdateBlinker(); - uint8_t sc = scBuf[0]; + const KeyScanCodes &sc = scBuf.Key; switch (sc & ~KEY_PRESSED) { case KEY_LEFT_CTRL: @@ -291,15 +288,15 @@ void StartKernelShell() for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { - if (strncmp(strBuf.c_str(), commands[i].Name, strBuf.size()) == 0) - { - strBuf = commands[i].Name; - for (size_t i = 0; i < strlen(strBuf.c_str()); i++) - Display->Print(strBuf[i]); - seekCount = bsCount = strBuf.size(); - Display->UpdateBuffer(); - break; - } + if (strncmp(strBuf.c_str(), commands[i].Name, strBuf.size()) != 0) + continue; + + strBuf = commands[i].Name; + for (size_t i = 0; i < strlen(strBuf.c_str()); i++) + Display->Print(strBuf[i]); + seekCount = bsCount = strBuf.size(); + Display->UpdateBuffer(); + break; } continue; } @@ -714,7 +711,7 @@ void StartKernelShell() Found = true; - std::string arg_only; + std::string arg_only = ""; const char *cmd_name = commands[i].Name; for (size_t i = strlen(cmd_name) + 1; i < strBuf.length(); i++) arg_only += strBuf[i]; diff --git a/library/cbuf.cpp b/library/cbuf.cpp deleted file mode 100644 index 08bd63ce..00000000 --- a/library/cbuf.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -CircularBuffer::CircularBuffer(size_t Size) - : Buffer(new uint8_t[Size]), - BufferSize(Size), - BufferCount(0), - Head(0), - Tail(0) {} - -CircularBuffer::~CircularBuffer() { delete[] Buffer; } - -size_t CircularBuffer::Write(const uint8_t *Data, size_t Size) -{ - sl_guard(Lock); - - size_t written = 0; - while (Size > 0) - { - if (BufferCount == BufferSize) - break; - - Buffer[Head] = *Data++; - Head = (Head + 1) % BufferSize; - BufferCount++; - written++; - Size--; - } - - return written; -} - -size_t CircularBuffer::Read(uint8_t *Data, size_t Size) -{ - sl_guard(Lock); - - size_t read = 0; - while (Size > 0) - { - if (BufferCount == 0) - break; - - *Data++ = Buffer[Tail]; - Tail = (Tail + 1) % BufferSize; - BufferCount--; - read++; - Size--; - } - - return read; -} - -size_t CircularBuffer::Peek(uint8_t *Data, size_t Size) -{ - sl_guard(Lock); - - size_t read = 0; - size_t tail = Tail; - while (Size > 0) - { - if (read == BufferCount) - break; - - *Data++ = Buffer[tail]; - tail = (tail + 1) % BufferSize; - read++; - Size--; - } - - return read; -} - -size_t CircularBuffer::Count() -{ - sl_guard(Lock); - return BufferCount; -} - -size_t CircularBuffer::Free() -{ - sl_guard(Lock); - return BufferSize - BufferCount; -} diff --git a/storage/cache.cpp b/storage/cache.cpp index cbe3be1c..ec5a7b1c 100644 --- a/storage/cache.cpp +++ b/storage/cache.cpp @@ -26,30 +26,140 @@ namespace vfs { - FileNode *Virtual::__CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName) + FileNode *Virtual::CacheSearchReturnLast(FileNode *Parent, const char **Path) + { + assert(Parent != nullptr); + + struct cwk_segment segment; + if (!cwk_path_get_first_segment(*Path, &segment)) + ReturnLogError(nullptr, "Failed to get first segment of path"); + + size_t segments = 0; + while (cwk_path_get_next_segment(&segment)) + segments++; + + if (segments == 0) + return Parent; + + const char *path = *Path; + if (strncmp(path, "\002root-", 6) == 0) /* FIXME: deduce the index */ + { + path += 6; + while (*path != '\0' && *path != '\003') + path++; + if (*path == '\003') + path++; + } + else + path = *Path; + + FileNode *__Parent = Parent; + if (this->PathIsAbsolute(path)) + { + while (__Parent->Parent) + __Parent = __Parent->Parent; + } + + cwk_path_get_first_segment(path, &segment); + do + { + std::string segmentName(segment.begin, segment.size); + + bool found = false; + for (FileNode *fn : __Parent->Children) + { + if (fn->Name != segmentName) + continue; + + cwk_segment __seg = segment; + assert(cwk_path_get_next_segment(&__seg)); /* There's something wrong */ + + __Parent = fn; + found = true; + break; + } + + if (!found) + { + *Path = segment.begin; + break; + } + } while (cwk_path_get_next_segment(&segment)); + + return __Parent; + } + + FileNode *Virtual::CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName) { if (Root == nullptr) return nullptr; - if (IsName) + debug("%s cache search for \"%s\" in \"%s\"", IsName ? "Relative" : "Absolute", NameOrPath, Root->Path.c_str()); + + struct cwk_segment segment; + if (!cwk_path_get_first_segment(NameOrPath, &segment)) + ReturnLogError(nullptr, "Failed to get first segment of path"); + + size_t segments = 0; + while (cwk_path_get_next_segment(&segment)) + segments++; + + if (IsName && segments == 0) { - if (strcmp(Root->Name.c_str(), NameOrPath) == 0) - return Root; + for (FileNode *fn : Root->Children) + { + if (fn->Name == NameOrPath) + return fn; + } + + ReturnLogError(nullptr, "Failed to find \"%s\" in \"%s\"", NameOrPath, Root->Path.c_str()); + } + + const char *path = NameOrPath; + if (strncmp(path, "\002root-", 6) == 0) /* FIXME: deduce the index */ + { + path += 6; + while (*path != '\0' && *path != '\003') + path++; + if (*path == '\003') + path++; } else + path = NameOrPath; + + FileNode *__Parent = Root; + if (this->PathIsAbsolute(path)) { - if (strcmp(Root->Path.c_str(), NameOrPath) == 0) - return Root; + /* Get the root if Root is not the root 【・_・?】 */ + while (__Parent->Parent) + __Parent = __Parent->Parent; } - for (const auto &Child : Root->Children) + cwk_path_get_first_segment(path, &segment); + do { - FileNode *ret = __CacheRecursiveSearch(Child, NameOrPath, IsName); - if (ret) - return ret; - } + std::string segmentName(segment.begin, segment.size); - debug("Failed to find %s in %s", NameOrPath, Root->Path.c_str()); + bool found = false; + for (FileNode *fn : __Parent->Children) + { + if (fn->Name != segmentName) + continue; + + cwk_segment __seg = segment; + if (!cwk_path_get_next_segment(&__seg)) + return fn; + + __Parent = fn; + found = true; + break; + } + + if (!found) + break; + } while (cwk_path_get_next_segment(&segment)); + + debug("Failed to find \"%s\" in \"%s\"", NameOrPath, Root->Path.c_str()); return nullptr; } @@ -57,35 +167,17 @@ namespace vfs { FileNode *rootNode = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0); - FileNode *ret = __CacheRecursiveSearch(rootNode, Path, false); + FileNode *ret = CacheRecursiveSearch(rootNode, Path, false); if (ret) return ret; debug("Path \"%s\" not found", Path); return nullptr; - __unreachable; - - debug("Path \"%s\" not found; attempting to search by segments", Path); - /* FIXME: This may not be the greatest idea */ - - struct cwk_segment segment; - if (!cwk_path_get_first_segment(Path, &segment)) - return __CacheRecursiveSearch(rootNode, Path, true); - - do - { - std::string segmentStr(segment.begin, segment.size); - ret = __CacheRecursiveSearch(rootNode, segmentStr.c_str(), true); - if (ret) - return ret; - } while (cwk_path_get_next_segment(&segment)); - - return nullptr; } FileNode *Virtual::CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode) { - FileNode *fn = new FileNode(); + FileNode *fn = new FileNode; fn->Name = Name; if (Parent) { @@ -107,7 +199,7 @@ namespace vfs int Virtual::RemoveCacheNode(FileNode *Node) { if (Node == nullptr) - return -1; + return -EINVAL; if (Node->Parent) { diff --git a/storage/filesystem.cpp b/storage/filesystem.cpp index d60b51dc..2c2fd24c 100644 --- a/storage/filesystem.cpp +++ b/storage/filesystem.cpp @@ -31,49 +31,6 @@ namespace vfs return cwk_path_is_relative(Path); } - dev_t Virtual::EarlyReserveDevice() - { - RegisterLock.store(true); - size_t len = DeviceMap.size(); - return len; - } - - int Virtual::LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root) - { - auto it = DeviceMap.find(Device); - if (it != DeviceMap.end()) - ReturnLogError(-EEXIST, "Device %d already registered", Device); - - FSMountInfo fsmi{.fsi = fsi, .Root = Root}; - DeviceMap.insert({Device, fsmi}); - RegisterLock.store(false); - return 0; - } - - dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi, Inode *Root) - { - RegisterLock.store(true); - size_t len = DeviceMap.size(); - FSMountInfo fsmi{.fsi = fsi, .Root = Root}; - DeviceMap.insert({len, fsmi}); - RegisterLock.store(false); - return len; - } - - int Virtual::UnregisterFileSystem(dev_t Device) - { - auto it = DeviceMap.find(Device); - if (it == DeviceMap.end()) - ReturnLogError(-ENOENT, "Device %d not found", Device); - - if (it->second.fsi->SuperOps.Synchronize) - it->second.fsi->SuperOps.Synchronize(it->second.fsi, NULL); - if (it->second.fsi->SuperOps.Destroy) - it->second.fsi->SuperOps.Destroy(it->second.fsi); - DeviceMap.erase(it); - return 0; - } - void Virtual::AddRoot(Inode *Root) { SmartLock(VirtualLock); @@ -88,9 +45,15 @@ namespace vfs Inode *RootNode = FileSystemRoots->Children[Index]; char rootName[128]{}; - snprintf(rootName, sizeof(rootName), "root-%ld", Index); + snprintf(rootName, sizeof(rootName), "\002root-%ld\003", Index); - return this->CreateCacheNode(nullptr, RootNode, rootName, 0); + auto it = FileRoots.find(Index); + if (it != FileRoots.end()) + return it->second; + + FileNode *ret = this->CreateCacheNode(nullptr, RootNode, rootName, 0); + FileRoots.insert({Index, ret}); + return ret; } FileNode *Virtual::Create(FileNode *Parent, const char *Name, mode_t Mode) @@ -126,34 +89,93 @@ namespace vfs return this->Create(Parent, Name, Mode); } + FileNode *Virtual::Mount(FileNode *Parent, Inode *Node, const char *Path) + { + char *path = strdup(Path); + char *lastSlash = strrchr(path, '/'); + if (lastSlash == path) + lastSlash++; + *lastSlash = '\0'; + + FileNode *parentNode = this->GetByPath(path, Parent); + free(path); + lastSlash = strrchr(Path, '/'); + lastSlash++; + return this->CreateCacheNode(parentNode, Node, lastSlash, Node->Mode); + } + + int Virtual::Unmount(const char *Path) + { + FileNode *node = this->GetByPath(Path, nullptr); + if (node == nullptr) + ReturnLogError(-ENOENT, "Path %s not found", Path); + + return this->RemoveCacheNode(node); + } + FileNode *Virtual::GetByPath(const char *Path, FileNode *Parent) { - FileNode *fn = this->CacheLookup(Path); - if (fn) - return fn; - if (Parent == nullptr) Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0); - auto it = DeviceMap.find(Parent->Node->Device); - if (it == DeviceMap.end()) - ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device); + if (strcmp(Path, ".") == 0) + return Parent; + + if (strcmp(Path, "..") == 0) + return Parent->Parent ? Parent->Parent : Parent; + + FileNode *fn = this->CacheRecursiveSearch(Parent, Path, this->PathIsRelative(Path)); + if (fn) + return fn; + + if (strncmp(Path, "\002root-", 6) == 0) /* FIXME: deduce the index */ + { + Path += 7; + while (*Path != '\0' && *Path != '\003') + Path++; + if (*Path == '\003') + Path++; + } + + FileNode *__Parent = CacheSearchReturnLast(Parent, &Path); struct cwk_segment segment; if (!cwk_path_get_first_segment(Path, &segment)) + { + auto it = DeviceMap.find(Parent->Node->Device); + if (unlikely(it == DeviceMap.end())) + ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device); + + if (it->second.fsi->Ops.Lookup == NULL) + ReturnLogError(nullptr, "Lookup not supported for %d", it->first); + + Inode *Node = NULL; + int ret = it->second.fsi->Ops.Lookup(Parent->Node, Path, &Node); + if (ret < 0) + ReturnLogError(nullptr, "Lookup for \"%s\"(%d) failed with %d", Path, it->first, ret); + + if (Parent->Node == Node) /* root / */ + { + debug("Returning root (%#lx)", Node); + return Parent; + } ReturnLogError(nullptr, "Path has no segments"); + } Inode *Node = NULL; - FileNode *__Parent = Parent; do { + auto it = DeviceMap.find(__Parent->Node->Device); + if (unlikely(it == DeviceMap.end())) + ReturnLogError(nullptr, "Device %d not found", __Parent->Node->Device); + if (it->second.fsi->Ops.Lookup == NULL) ReturnLogError(nullptr, "Lookup not supported for %d", it->first); std::string segmentName(segment.begin, segment.size); int ret = it->second.fsi->Ops.Lookup(__Parent->Node, segmentName.c_str(), &Node); if (ret < 0) - ReturnLogError(nullptr, "Lookup for %d failed with %d", it->first, ret); + ReturnLogError(nullptr, "Lookup for \"%s\"(%d) failed with %d", segmentName.c_str(), it->first, ret); __Parent = this->CreateCacheNode(__Parent, Node, segmentName.c_str(), 0); } while (cwk_path_get_next_segment(&segment)); @@ -161,6 +183,10 @@ namespace vfs if (!ret->IsDirectory()) return ret; + auto it = DeviceMap.find(__Parent->Node->Device); + if (unlikely(it == DeviceMap.end())) + ReturnLogError(nullptr, "Device %d not found", __Parent->Node->Device); + size_t dirAllocLen = sizeof(struct kdirent) + strlen(Path); struct kdirent *dirent = (struct kdirent *)malloc(dirAllocLen); size_t offset = 2; /* Skip . and .. */ @@ -180,6 +206,34 @@ namespace vfs return ret; } + std::string Virtual::GetByNode(FileNode *Node) + { + if (Node->Parent == nullptr) + { + if (Node->Node->Flags & I_FLAG_ROOT) + return Node->fsi->RootName; + assert(Node->Parent != nullptr); + } + + std::string path; + + auto appendPath = [&path](const char *name) + { + if (path.size() > 0) + path += "/"; + path += name; + }; + + FileNode *current = Node; + while (current->Parent != nullptr) + { + appendPath(current->Name.c_str()); + current = current->Parent; + } + + return path; + } + FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, const char *Target) { auto it = DeviceMap.find(Parent->Node->Device); diff --git a/storage/fs/ustar.cpp b/storage/fs/ustar.cpp index 4b5aaa6f..29a458bb 100644 --- a/storage/fs/ustar.cpp +++ b/storage/fs/ustar.cpp @@ -143,7 +143,7 @@ namespace vfs }; FileHeader *hdr = new FileHeader{}; - SetMode(Mode, hdr); + SetMode(inode.Mode, hdr); strncpy(hdr->name, basename, sizeof(hdr->name)); strncpy(hdr->signature, TMAGIC, TMAGLEN); strncpy(hdr->version, TVERSION, TVERSLEN); @@ -205,12 +205,14 @@ namespace vfs } memcpy(Buffer, (uint8_t *)((uintptr_t)node->Header + sizeof(FileHeader) + Offset), Size); - debug("Read %d bytes from %d[%d]", Size, Node->Index, Offset); + // debug("Read %d bytes from %d[%d]", Size, Node->Index, Offset); return Size; } - ssize_t USTAR::ReadDir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + __no_sanitize("alignment") + ssize_t USTAR::ReadDir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { + /* FIXME: FIX ALIGNMENT FOR DIRENT! */ auto Node = (USTARInode *)_Node; off_t realOffset = Offset; @@ -321,6 +323,15 @@ namespace vfs entries++; } + if (totalSize + sizeof(struct kdirent) >= Size) + return totalSize; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = 0; + ent->d_off = 0; + ent->d_reclen = 0; + ent->d_type = DT_UNKNOWN; + ent->d_name[0] = '\0'; return totalSize; } @@ -809,7 +820,8 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size) FileSystemInfo *fsi = new FileSystemInfo; fsi->Name = "ustar"; - fsi->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + fsi->RootName = "/"; + fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; fsi->SuperOps.DeleteInode = __ustar_DestroyInode; fsi->SuperOps.Destroy = __ustar_Destroy; fsi->Ops.Lookup = __ustar_Lookup; diff --git a/storage/virtual.cpp b/storage/virtual.cpp index ce921115..4d43f4cc 100644 --- a/storage/virtual.cpp +++ b/storage/virtual.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include "../kernel.h" @@ -52,7 +51,7 @@ namespace vfs foreach (const auto &Root in Parent->Children) { char rootName[128]{}; - snprintf(rootName, sizeof(rootName), "root-%ld", offset); + snprintf(rootName, sizeof(rootName), "\x02root-%ld\x03", offset); if (strcmp(rootName, Name) == 0) { @@ -71,78 +70,9 @@ namespace vfs assert(!"Not implemented"); } - ssize_t __vfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) - { - switch (Node->GetMinor()) - { - case 2: /* /dev/null */ - { - return 0; - } - case 3: /* /dev/zero */ - { - if (Size <= 0) - return 0; - - memset(Buffer, 0, Size); - return Size; - } - case 4: /* /dev/random */ - { - if (Size <= 0) - return 0; - - if (Size < sizeof(uint64_t)) - { - uint8_t *buf = (uint8_t *)Buffer; - for (size_t i = 0; i < Size; i++) - buf[i] = (uint8_t)(Random::rand16() & 0xFF); - return Size; - } - - uint64_t *buf = (uint64_t *)Buffer; - for (size_t i = 0; i < Size / sizeof(uint64_t); i++) - buf[i] = Random::rand64(); - return Size; - } - case 5: /* /dev/mem */ - { - stub; - return 0; - } - default: - return -ENOENT; - }; - } - - ssize_t __vfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) - { - switch (Node->GetMinor()) - { - case 2: /* /dev/null */ - { - return Size; - } - case 3: /* /dev/zero */ - { - return Size; - } - case 4: /* /dev/random */ - { - return Size; - } - case 5: /* /dev/mem */ - { - stub; - return 0; - } - default: - return -ENOENT; - }; - } - /* This implementation is used internally by the kernel, so no "." & ".." */ - ssize_t __vfs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + __no_sanitize("alignment") + ssize_t __vfs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { if (_Node->GetMinor() != 0) { @@ -189,6 +119,15 @@ namespace vfs if (ent) ent->d_off = INT32_MAX; + if (totalSize + sizeof(struct kdirent) >= Size) + return totalSize; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = 0; + ent->d_off = 0; + ent->d_reclen = 0; + ent->d_type = DT_UNKNOWN; + ent->d_name[0] = '\0'; return totalSize; } @@ -222,13 +161,9 @@ namespace vfs S_IRWXG | S_IRWXO | S_IFDIR; - FileNode *dev = this->ForceCreate(this->GetRoot(0), "dev", mode); - FileNode *mnt = this->ForceCreate(this->GetRoot(0), "mnt", mode); FileNode *proc = this->ForceCreate(this->GetRoot(0), "proc", mode); FileNode *log = this->ForceCreate(this->GetRoot(0), "var", mode); log = this->ForceCreate(log, "log", mode); - dev->Node->Flags = iFlags; - mnt->Node->Flags = iFlags; proc->Node->Flags = iFlags; log->Node->Flags = iFlags; @@ -242,49 +177,54 @@ namespace vfs self->Node->SetDevice(0, 1); self->Node->Flags = iFlags; - /* c rw- rw- rw- */ - mode = S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP | - S_IROTH | S_IWOTH | - S_IFCHR; - FileNode *null = this->ForceCreate(dev, "null", mode); - null->Node->Device = FileSystemRoots->Node.Device; - null->Node->SetDevice(0, 2); - null->Node->Flags = iFlags; - - /* c rw- rw- rw- */ - mode = S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP | - S_IROTH | S_IWOTH | - S_IFCHR; - FileNode *zero = this->ForceCreate(dev, "zero", mode); - zero->Node->Device = FileSystemRoots->Node.Device; - zero->Node->SetDevice(0, 3); - zero->Node->Flags = iFlags; - - /* c rw- rw- rw- */ - mode = S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP | - S_IROTH | S_IWOTH | - S_IFCHR; - FileNode *random = this->ForceCreate(dev, "random", mode); - random->Node->Device = FileSystemRoots->Node.Device; - random->Node->SetDevice(0, 4); - random->Node->Flags = iFlags; - - /* c rw- r-- --- */ - mode = S_IRUSR | S_IWUSR | - S_IRGRP | - - S_IFCHR; - FileNode *mem = this->ForceCreate(dev, "mem", mode); - mem->Node->Device = FileSystemRoots->Node.Device; - mem->Node->SetDevice(0, 5); - mem->Node->Flags = iFlags; - new vfs::PTMXDevice(); } + dev_t Virtual::EarlyReserveDevice() + { + RegisterLock.store(true); + size_t len = DeviceMap.size(); + return len; + } + + int Virtual::LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root) + { + auto it = DeviceMap.find(Device); + if (it != DeviceMap.end()) + ReturnLogError(-EEXIST, "Device %d already registered", Device); + + Root->Flags |= I_FLAG_ROOT; + FSMountInfo fsmi{.fsi = fsi, .Root = Root}; + DeviceMap.insert({Device, fsmi}); + RegisterLock.store(false); + return 0; + } + + dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi, Inode *Root) + { + RegisterLock.store(true); + size_t len = DeviceMap.size(); + Root->Flags |= I_FLAG_ROOT; + FSMountInfo fsmi{.fsi = fsi, .Root = Root}; + DeviceMap.insert({len, fsmi}); + RegisterLock.store(false); + return len; + } + + int Virtual::UnregisterFileSystem(dev_t Device) + { + auto it = DeviceMap.find(Device); + if (it == DeviceMap.end()) + ReturnLogError(-ENOENT, "Device %d not found", Device); + + if (it->second.fsi->SuperOps.Synchronize) + it->second.fsi->SuperOps.Synchronize(it->second.fsi, NULL); + if (it->second.fsi->SuperOps.Destroy) + it->second.fsi->SuperOps.Destroy(it->second.fsi); + DeviceMap.erase(it); + return 0; + } + Virtual::Virtual() { SmartLock(VirtualLock); @@ -297,19 +237,18 @@ namespace vfs S_IROTH | S_IXOTH | S_IFDIR; - FileSystemRoots->Node.Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + FileSystemRoots->Node.Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; FileSystemRoots->Node.Offset = INT32_MAX; FileSystemRoots->Name = ""; FileSystemInfo *fsi = new FileSystemInfo; fsi->Name = "Virtual Roots"; - fsi->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; + fsi->RootName = "ROOT"; + fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; fsi->SuperOps = {}; fsi->Ops.Lookup = __vfs_Lookup; fsi->Ops.Create = __vfs_Create; - fsi->Ops.Read = __vfs_Read; - fsi->Ops.Write = __vfs_Write; fsi->Ops.ReadDir = __vfs_Readdir; fsi->Ops.ReadLink = __vfs_ReadLink; diff --git a/tasking/task.cpp b/tasking/task.cpp index 668cf681..279496f5 100644 --- a/tasking/task.cpp +++ b/tasking/task.cpp @@ -62,7 +62,7 @@ namespace Tasking return ((Scheduler::Base *)Scheduler)->GetProcessByID(ID); } - TCB *Task::GetThreadByID(TID ID, PCB* Parent) + TCB *Task::GetThreadByID(TID ID, PCB *Parent) { return ((Scheduler::Base *)Scheduler)->GetThreadByID(ID, Parent); }