diff --git a/Drivers/include/block.h b/Drivers/include/block.h new file mode 100644 index 00000000..45c6ce29 --- /dev/null +++ b/Drivers/include/block.h @@ -0,0 +1,110 @@ +/* + 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_BLOCK_H__ +#define __FENNIX_API_BLOCK_H__ + +#include + +#if __has_include() +#include +#else +#include +#endif + +struct BlockDevice +{ + /** + * @brief Base name of the device. + * + * This name is used to identify the device in the system. It should be unique + * across all block devices. The kernel may append a number to this name to + * create a unique device name (e.g., "ahci0", "ahci1"). + */ + const char *Name; + + /** + * @brief Total size of the device in bytes. + * + * This value represents the total addressable storage capacity of the device. + * It is used for bounds checking and partitioning. + */ + size_t Size; + + /** + * @brief Size of a single block in bytes. + * + * All read and write operations are performed in multiples of this block size. + * Typical values are 512 or 4096 bytes. + */ + uint32_t BlockSize; + + /** + * @brief Number of blocks in the device. + * + * This value is calculated as Size / BlockSize. It represents the total number + * of addressable blocks on the device. + */ + size_t BlockCount; + + /** + * @brief Pointer to the block device operations structure. + * + * This structure contains function pointers for various operations that can + * be performed on the block device, such as read, write, and ioctl. + * + * Yea, inode operations are used for block devices too. + */ + const InodeOperations *Ops; + + /** + * @brief Opaque pointer to driver-specific or hardware-specific data. + * + * This field allows the driver to associate private context or state with the + * device, such as controller registers or internal buffers. + */ + void *PrivateData; +}; + +#ifndef __kernel__ +/** + * @brief Registers a block device with the kernel block subsystem. + * + * This function should be called by block device drivers after initializing + * a device. The kernel will take ownership of the device structure and assign + * it a unique device ID. The device will then be accessible for filesystem + * mounting and I/O operations. + * + * @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device. + * @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure. + */ +dev_t RegisterBlockDevice(struct BlockDevice *Device); + +/** + * @brief Unregisters a block device from the kernel block subsystem. + * + * This function should be called by drivers when a device is being removed + * or is no longer available. The kernel will release any resources associated + * with the device and invalidate its device ID. + * + * @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice(). + * @return 0 on success, or an error code. + */ +int UnregisterBlockDevice(dev_t DeviceID); +#endif // __kernel__ + +#endif // __FENNIX_API_BLOCK_H__ diff --git a/Drivers/include/fs.h b/Drivers/include/fs.h index 3abe9a75..c55969d5 100644 --- a/Drivers/include/fs.h +++ b/Drivers/include/fs.h @@ -322,10 +322,6 @@ struct InodeOperations 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 { @@ -337,8 +333,8 @@ struct SuperBlockOperations * * Write all pending changes to the disk. * - * @param Info Inode to synchronize. If NULL, synchronize all inodes. - * @param Node Inode to synchronize. + * @param Info Inode to synchronize. + * @param Node Inode to synchronize. If NULL, synchronize all inodes. * * @return Zero on success, otherwise an error code. */ @@ -354,13 +350,50 @@ struct SuperBlockOperations * @return Zero on success, otherwise an error code. */ int (*Destroy)(struct FileSystemInfo *Info); + + /** + * Probe the filesystem. + * + * Check if the filesystem is supported by the driver. + * + * @param Device Device to probe. + * + * @return Zero on success, otherwise an error code. + */ + int (*Probe)(void *Device); + + /** + * Mount the filesystem. + * + * Mount the filesystem on the given device. + * + * @param FS Filesystem to mount. + * @param Root Pointer to the root inode. + * @param Device Device to mount. + * + * @return Zero on success, otherwise an error code. + */ + int (*Mount)(struct FileSystemInfo *FS, struct Inode **Root, void *Device); + + /** + * Unmount the filesystem. + * + * Unmount the filesystem from the given device. + * + * @param FS Filesystem to unmount. + * + * @return Zero on success, otherwise an error code. + */ + int (*Unmount)(struct FileSystemInfo *FS); } __attribute__((packed)); struct FileSystemInfo { const char *Name; - const char *RootName; + int Flags; + int Capabilities; + struct SuperBlockOperations SuperOps; struct InodeOperations Ops; @@ -368,6 +401,9 @@ struct FileSystemInfo } __attribute__((packed)); #ifndef __kernel__ +dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root); +int UnregisterMountPoint(dev_t Device); + dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root); int UnregisterFileSystem(dev_t Device); #endif // !__kernel__ diff --git a/Kernel/TODO.md b/Kernel/TODO.md index 9d9a64bd..cd5a33fd 100644 --- a/Kernel/TODO.md +++ b/Kernel/TODO.md @@ -9,7 +9,7 @@ - [ ] ~~Do not map the entire memory. Map only the needed memory address at allocation time.~~ (we just copy the pages for userland, see `Fork()` inside [core/memory/page_table.cpp](core/memory/page_table.cpp)) - [ ] Implementation of logging (beside serial) with log rotation. - [x] Implement a better task manager. (replace struct P/TCB with classes) -- [ ] Rewrite virtual file system. +- [x] Rewrite virtual file system. - [ ] Colors in crash screen are not following the kernel color scheme. - [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly) - [ ] Rework PSF1 font loader. diff --git a/Kernel/core/console.cpp b/Kernel/core/console.cpp index a89f014e..f36bba05 100644 --- a/Kernel/core/console.cpp +++ b/Kernel/core/console.cpp @@ -156,15 +156,15 @@ namespace KernelConsole bool SetTheme(std::string Theme) { - FileNode *rn = fs->GetByPath("/sys/cfg/term", thisProcess->Info.RootNode); + Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term"); if (rn == nullptr) return false; - kstat st{}; - rn->Stat(&st); + kstat st; + fs->Stat(rn, &st); char *sh = new char[st.Size]; - rn->Read(sh, st.Size, 0); + fs->Read(rn, sh, st.Size, 0); ini_t *ini = ini_load(sh, NULL); int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx; @@ -370,16 +370,16 @@ namespace KernelConsole void LateInit() { - FileNode *rn = fs->GetByPath("/sys/cfg/term", thisProcess->Info.RootNode); + Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term"); if (rn == nullptr) return; { kstat st; - rn->Stat(&st); + fs->Stat(rn, &st); std::string cfg; - cfg.reserve(st.Size); - rn->Read(cfg.data(), st.Size, 0); + cfg.resize(st.Size); + fs->Read(rn, cfg.data(), st.Size, 0); LoadConsoleConfig(cfg); } diff --git a/Kernel/core/driver/api.cpp b/Kernel/core/driver/api.cpp index bc424a4c..a44e8741 100644 --- a/Kernel/core/driver/api.cpp +++ b/Kernel/core/driver/api.cpp @@ -191,11 +191,11 @@ namespace v0 /* --------- */ - dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root) + dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info) { - dbg_api("%d, %#lx, %#lx", DriverID, Info, Root); + dbg_api("%d, %#lx", DriverID, Info); - return fs->RegisterFileSystem(Info, Root); + return fs->RegisterFileSystem(Info); } int UnregisterFileSystem(dev_t DriverID, dev_t Device) @@ -710,6 +710,20 @@ namespace v0 return DriverManager->ReportInputEvent(DriverID, Report); } + + dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device) + { + dbg_api("%d, %#lx", DriverID, Device); + + return DriverManager->RegisterBlockDevice(DriverID, Device); + } + + int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID) + { + dbg_api("%d, %d", DriverID, DeviceID); + + return DriverManager->UnregisterBlockDevice(DriverID, DeviceID); + } } struct APISymbols @@ -777,6 +791,8 @@ static struct APISymbols APISymbols_v0[] = { {"__RegisterDevice", (void *)v0::RegisterDevice}, {"__UnregisterDevice", (void *)v0::UnregisterDevice}, {"__ReportInputEvent", (void *)v0::ReportInputEvent}, + {"__RegisterBlockDevice", (void *)v0::RegisterBlockDevice}, + {"__UnregisterBlockDevice", (void *)v0::UnregisterBlockDevice}, }; long __KernelUndefinedFunction(long arg0, long arg1, long arg2, long arg3, diff --git a/Kernel/core/driver/daemon.cpp b/Kernel/core/driver/daemon.cpp deleted file mode 100644 index e97d5297..00000000 --- a/Kernel/core/driver/daemon.cpp +++ /dev/null @@ -1,726 +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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../kernel.h" - -using namespace vfs; - -namespace Driver -{ - /** - * maj = 0 - * min: - * 0 - - * 1 - /proc/self - * - * maj = 1 - * min: - * 0 - /dev/input/keyboard - * 1 - /dev/input/mouse - * ..- /dev/input/eventN - */ - - int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) - { - func("%#lx %s %#lx", _Parent, Name, Result); - - assert(_Parent != nullptr); - - const char *basename; - size_t length; - cwk_path_get_basename(Name, &basename, &length); - if (basename == NULL) - { - error("Invalid name %s", Name); - return -EINVAL; - } - - auto Parent = (Manager::DeviceInode *)_Parent; - for (const auto &child : Parent->Children) - { - debug("Comparing %s with %s", basename, child->Name.c_str()); - 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) - { - func("%#lx %s %d", _Parent, Name, Mode); - - 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.Device = Parent->Node.Device; - _dev->Node.Mode = Mode; - _dev->Node.Index = Parent->Node.Index + Parent->Children.size(); - _dev->Node.Offset = 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) - { - func("%#lx %d %d", Node, Size, Offset); - switch (Node->GetMajor()) - { - 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) - { - func("%#lx %p %d %d", Node, Buffer, Size, Offset); - - switch (Node->GetMajor()) - { - 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); - } - } - } - - int __fs_Open(struct Inode *Node, int Flags, mode_t Mode) - { - func("%#lx %d %d", Node, Flags, Mode); - - switch (Node->GetMajor()) - { - case 1: - { - switch (Node->GetMinor()) - { - case 0: /* /dev/input/keyboard */ - 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->Open, -ENOTSUP); - return dOps->second.Ops->Open(Node, Flags, Mode); - } - } - } - - int __fs_Close(struct Inode *Node) - { - func("%#lx", Node); - - switch (Node->GetMajor()) - { - case 1: - { - switch (Node->GetMinor()) - { - case 0: /* /dev/input/keyboard */ - 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->Close, -ENOTSUP); - return dOps->second.Ops->Close(Node); - } - } - } - - int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp) - { - func("%#lx %lu %#lx", Node, Request, Argp); - - switch (Node->GetMajor()) - { - case 1: - { - switch (Node->GetMinor()) - { - case 0: /* /dev/input/keyboard */ - case 1: /* /dev/input/mouse */ - return -ENOSYS; - 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->Ioctl, -ENOTSUP); - return dOps->second.Ops->Ioctl(Node, Request, Argp); - } - } - } - - __no_sanitize("alignment") - ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) - { - func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, 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) - { - debug("iterating \"%s\" inside \"%s\"", var->Name.c_str(), Node->Name.c_str()); - if (var->Node.Offset < realOffset) - { - debug("skipping \"%s\" (%d < %d)", var->Name.c_str(), 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_IFBLK; - - 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); - } - - dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, 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); - if (dOps != dop->end()) - continue; - - FileNode *node = fs->GetByPath(name, devNode); - if (node) - ReturnLogError(-EEXIST, "Device file %s already exists", name); - - node = fs->Create(devNode, name, mode); - if (node == nullptr) - ReturnLogError(-ENOMEM, "Failed to create device file %s", name); - - 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 */ - } - - 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; - } - - void *Manager::AllocateMemory(dev_t DriverID, size_t Pages) - { - 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 Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages) - { - auto itr = Drivers.find(DriverID); - assert(itr != Drivers.end()); - itr->second.vma->FreePages(Pointer, Pages); - } - - 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 = "Device Virtual File System"; - 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.Remove = nullptr; - fsi->Ops.Rename = nullptr; - fsi->Ops.Read = __fs_Read; - fsi->Ops.Write = __fs_Write; - fsi->Ops.Truncate = nullptr; - fsi->Ops.Open = __fs_Open; - fsi->Ops.Close = __fs_Close; - fsi->Ops.Ioctl = __fs_Ioctl; - fsi->Ops.ReadDir = __fs_Readdir; - fsi->Ops.MkDir = nullptr; - fsi->Ops.RmDir = nullptr; - fsi->Ops.SymLink = nullptr; - fsi->Ops.ReadLink = nullptr; - fsi->Ops.Seek = nullptr; - fsi->Ops.Stat = nullptr; - - dev->Device = fs->RegisterFileSystem(fsi, dev); - dev->SetDevice(0, MinorID++); - MinorID++; /* 1 = /proc/self */ - - 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; - input->Node.Offset = _dev->Children.size(); - _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; - device->Node.Offset = p1->Children.size(); - p1->Children.push_back(device); - }; - - 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/Kernel/core/driver/dev.cpp b/Kernel/core/driver/dev.cpp new file mode 100644 index 00000000..d21004c7 --- /dev/null +++ b/Kernel/core/driver/dev.cpp @@ -0,0 +1,483 @@ +/* + 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 "../../kernel.h" + +namespace Driver +{ + dev_t DeviceDirID; + + int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) + { + func("%#lx %s %#lx", _Parent, Name, Result); + + assert(_Parent != nullptr); + + const char *basename; + size_t length; + cwk_path_get_basename(Name, &basename, &length); + if (basename == NULL) + { + error("Invalid name %s", Name); + return -EINVAL; + } + + auto Parent = (Manager::DeviceInode *)_Parent; + for (const auto &child : Parent->Children) + { + debug("Comparing %s with %s", basename, child->Name.c_str()); + if (strcmp(child->Name.c_str(), basename) != 0) + continue; + + *Result = &child->inode; + return 0; + } + + debug("Not found %s", Name); + return -ENOENT; + } + + int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result) + { + func("%#lx %s %d", _Parent, Name, Mode); + + 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->inode.Device = Parent->inode.Device; + _dev->inode.Mode = Mode; + _dev->inode.Index = Parent->inode.Index + Parent->Children.size(); + _dev->inode.Offset = Parent->Children.size(); + Parent->Children.push_back(_dev); + + *Result = &_dev->inode; + return 0; + } + + ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) + { + func("%#lx %d %d", Node, Size, Offset); + + if ((dev_t)Node->GetMajor() == DeviceDirID) + { + 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; + }; + } + + 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) + { + func("%#lx %p %d %d", Node, Buffer, Size, Offset); + + if ((dev_t)Node->GetMajor() == DeviceDirID) + { + switch (Node->GetMinor()) + { + case 0: /* /dev/input/keyboard */ + { + return -ENOTSUP; + } + case 1: /* /dev/input/mouse */ + { + return -ENOTSUP; + } + default: + return -ENOENT; + }; + } + + 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); + } + + int __fs_Open(struct Inode *Node, int Flags, mode_t Mode) + { + func("%#lx %d %d", Node, Flags, Mode); + + if ((dev_t)Node->GetMajor() == DeviceDirID) + { + switch (Node->GetMinor()) + { + case 0: /* /dev/input/keyboard */ + case 1: /* /dev/input/mouse */ + return -ENOTSUP; + default: + return -ENOENT; + }; + } + + 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->Open, -ENOTSUP); + return dOps->second.Ops->Open(Node, Flags, Mode); + } + + int __fs_Close(struct Inode *Node) + { + func("%#lx", Node); + + if ((dev_t)Node->GetMajor() == DeviceDirID) + { + switch (Node->GetMinor()) + { + case 0: /* /dev/input/keyboard */ + case 1: /* /dev/input/mouse */ + return -ENOTSUP; + default: + return -ENOENT; + }; + } + + 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->Close, -ENOTSUP); + return dOps->second.Ops->Close(Node); + } + + int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp) + { + func("%#lx %lu %#lx", Node, Request, Argp); + + if ((dev_t)Node->GetMajor() == DeviceDirID) + { + switch (Node->GetMinor()) + { + case 0: /* /dev/input/keyboard */ + case 1: /* /dev/input/mouse */ + return -ENOSYS; + default: + return -ENOENT; + }; + } + + 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->Ioctl, -ENOTSUP); + return dOps->second.Ops->Ioctl(Node, Request, Argp); + } + + __no_sanitize("alignment") ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + { + func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries); + + auto node = (Manager::DeviceInode *)_Node; + off_t realOffset = Offset; + size_t totalSize = 0; + uint16_t reclen = 0; + struct kdirent *ent = nullptr; + + if (!S_ISDIR(node->inode.Mode)) + return -ENOTDIR; + + 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->inode.Index; + ent->d_off = 0; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, "."); + totalSize += reclen; + Offset++; + } + + if (Offset == 1) + { + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1); + if (totalSize + reclen > Size) + return totalSize; + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + if (node->Parent) + ent->d_ino = node->Parent->inode->Index; + else if (node->ParentInode) + ent->d_ino = node->ParentInode->Index; + else + ent->d_ino = node->inode.Index; + ent->d_off = 1; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, ".."); + totalSize += reclen; + Offset++; + } + + off_t entryIndex = 0; + for (const auto &var : node->Children) + { + if (entryIndex + 2 < realOffset) + { + entryIndex++; + continue; + } + if (Entries && entryIndex >= 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->inode.Index; + ent->d_off = entryIndex + 2; + ent->d_reclen = reclen; + ent->d_type = IFTODT(var->inode.Mode); + strcpy(ent->d_name, var->Name.c_str()); + totalSize += reclen; + entryIndex++; + } + + if (totalSize + offsetof(struct kdirent, d_name) + 1 > 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; + } + + int __fs_Stat(struct Inode *_Node, struct kstat *Stat) + { + func("%#lx %#lx", _Node, Stat); + auto node = (Manager::DeviceInode *)_Node; + + assert(node != nullptr); + assert(Stat != nullptr); + + Stat->Device = node->inode.Device; + Stat->Index = node->inode.Index; + Stat->HardLinks = 1; + Stat->UserID = 0; + Stat->GroupID = 0; + Stat->RawDevice = node->inode.RawDevice; + Stat->Size = node->Size; + Stat->AccessTime = node->AccessTime; + Stat->ModifyTime = node->ModifyTime; + Stat->ChangeTime = node->ChangeTime; + Stat->BlockSize = node->BlockSize; + Stat->Blocks = node->Blocks; + Stat->Attribute = 0; + + return 0; + } + + void Manager::InitializeDeviceDirectory() + { + 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; + + FileSystemInfo *fsi = new FileSystemInfo; + fsi->Name = "Device Virtual File System"; + fsi->SuperOps = {}; + fsi->Ops.Lookup = __fs_Lookup; + fsi->Ops.Create = __fs_Create; + fsi->Ops.Remove = nullptr; + fsi->Ops.Rename = nullptr; + fsi->Ops.Read = __fs_Read; + fsi->Ops.Write = __fs_Write; + fsi->Ops.Truncate = nullptr; + fsi->Ops.Open = __fs_Open; + fsi->Ops.Close = __fs_Close; + fsi->Ops.Ioctl = __fs_Ioctl; + fsi->Ops.ReadDir = __fs_Readdir; + fsi->Ops.MkDir = nullptr; + fsi->Ops.RmDir = nullptr; + fsi->Ops.SymLink = nullptr; + fsi->Ops.ReadLink = nullptr; + fsi->Ops.Seek = nullptr; + fsi->Ops.Stat = __fs_Stat; + + DeviceDirID = dev->Device = fs->RegisterFileSystem(fsi); + dev->SetDevice(0, MinorID++); + + Node root = fs->GetRoot(0); + devNode = fs->Mount(root, dev, "dev", fsi); + assert(devNode->Parent != nullptr); + + _dev->Parent = devNode->Parent; + _dev->ParentInode = devNode->Parent->inode; + + /* d rwx r-- r-- */ + mode = S_IRWXU | + S_IRGRP | + S_IROTH | + S_IFDIR; + DeviceInode *blk = new DeviceInode; + blk->Parent = devNode; + blk->ParentInode = devNode->inode; + blk->Name = "block"; + blk->inode.Device = dev->Device; + blk->inode.Mode = mode; + blk->inode.Offset = _dev->Children.size(); + _dev->Children.push_back(blk); + devBlockNode = fs->Lookup(devNode, "block"); + + /* d rwx r-- r-- */ + mode = S_IRWXU | + S_IRGRP | + S_IROTH | + S_IFDIR; + DeviceInode *input = new DeviceInode; + input->Parent = devNode; + input->ParentInode = devNode->inode; + input->Name = "input"; + input->inode.Device = dev->Device; + input->inode.Mode = mode; + input->inode.Offset = _dev->Children.size(); + _dev->Children.push_back(input); + devInputNode = fs->Lookup(devNode, "input"); + + auto createDevice = [](DeviceInode *p1, Node p2, const std::string &name, dev_t maj, dev_t min, mode_t mode) + { + DeviceInode *device = new DeviceInode; + device->Parent = p2; + device->ParentInode = p2->inode; + device->Name = name; + device->inode.Device = p2->inode->Device; + device->inode.Mode = mode; + device->inode.SetDevice(maj, min); + device->inode.Offset = p1->Children.size(); + p1->Children.push_back(device); + }; + + MinorID = 0; + + /* c rw- r-- --- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | + + S_IFCHR; + createDevice(input, devInputNode, "keyboard", DeviceDirID, MinorID++, mode); + + /* c rw- r-- --- */ + mode = S_IRUSR | S_IWUSR | + S_IRGRP | + + S_IFCHR; + createDevice(input, devInputNode, "mouse", DeviceDirID, MinorID++, mode); + } +} diff --git a/Kernel/core/driver/driver.cpp b/Kernel/core/driver/driver.cpp index 413f94dc..e1a99cab 100644 --- a/Kernel/core/driver/driver.cpp +++ b/Kernel/core/driver/driver.cpp @@ -38,12 +38,12 @@ extern const __SIZE_TYPE__ trusted_drivers_count; namespace Driver { - bool Manager::IsDriverTrusted(FileNode *File) + bool Manager::IsDriverTrusted(Node File) { kstat st; - File->Stat(&st); + fs->Stat(File, &st); std::unique_ptr ptr(new uint8_t[st.Size]); - File->Read(ptr.get(), st.Size, 0); + fs->Read(File, ptr.get(), st.Size, 0); uint8_t *sha = sha512_sum(ptr.get(), st.Size); char hash_str[129]; for (int j = 0; j < 64; j++) @@ -102,7 +102,8 @@ namespace Driver } const char *DriverDirectory = Config.DriverDirectory; - FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr); + Node root = fs->GetRoot(0); + Node drvDirNode = fs->Lookup(root, DriverDirectory); if (!drvDirNode) { error("Failed to open driver directory %s", DriverDirectory); @@ -110,7 +111,7 @@ namespace Driver return; } - for (const auto &drvNode : drvDirNode->Children) + for (const auto &drvNode : fs->ReadDirectory(drvDirNode)) { debug("Checking driver %s", drvNode->Path.c_str()); if (!drvNode->IsRegularFile()) @@ -273,12 +274,12 @@ namespace Driver } } - int Manager::LoadDriverFile(DriverObject &Drv, FileNode *File) + int Manager::LoadDriverFile(DriverObject &Drv, Node File) { trace("Loading driver %s in memory", File->Name.c_str()); Elf_Ehdr ELFHeader{}; - File->Read(&ELFHeader, sizeof(Elf_Ehdr), 0); + fs->Read(File, &ELFHeader, sizeof(Elf_Ehdr), 0); AssertReturnError(ELFHeader.e_ident[EI_CLASS] == ELFCLASS64, -ENOEXEC); AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC); @@ -295,7 +296,7 @@ namespace Driver Elf_Phdr phdr{}; for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) { - File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); + fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); if (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC) { if (segSize < phdr.p_vaddr + phdr.p_memsz) @@ -306,7 +307,7 @@ namespace Driver if (phdr.p_type == PT_INTERP) { char interp[17]; - File->Read(interp, sizeof(interp), phdr.p_offset); + fs->Read(File, interp, sizeof(interp), phdr.p_offset); if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0) { error("Interpreter is not /boot/fennix.elf"); @@ -326,13 +327,13 @@ namespace Driver Elf_Shdr shstrtab{}; Elf_Shdr shdr{}; __DriverInfo driverInfo{}; - File->Read(&shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize)); + fs->Read(File, &shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize)); for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++) { if (i == ELFHeader.e_shstrndx) continue; - File->Read(&shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize)); + fs->Read(File, &shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize)); switch (shdr.sh_type) { @@ -350,11 +351,11 @@ namespace Driver } char symName[16]; - File->Read(symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name); + fs->Read(File, symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name); if (strcmp(symName, ".driver.info") != 0) continue; - File->Read(&driverInfo, sizeof(__DriverInfo), shdr.sh_offset); + fs->Read(File, &driverInfo, sizeof(__DriverInfo), shdr.sh_offset); /* Perform relocations */ driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name); @@ -367,13 +368,13 @@ namespace Driver { Elf_Sym symEntry{}; uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf_Sym)); - File->Read(&symEntry, sizeof(Elf_Sym), symOffset); + fs->Read(File, &symEntry, sizeof(Elf_Sym), symOffset); if (symEntry.st_name == 0) continue; char symName[16]; - File->Read(symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name); + fs->Read(File, symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name); switch (symEntry.st_shndx) { @@ -405,7 +406,7 @@ namespace Driver for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) { - File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); + fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); switch (phdr.p_type) { @@ -421,7 +422,7 @@ namespace Driver phdr.p_filesz, phdr.p_memsz); if (phdr.p_filesz > 0) - File->Read(dest, phdr.p_filesz, phdr.p_offset); + fs->Read(File, (void *)dest, phdr.p_filesz, phdr.p_offset); if (phdr.p_memsz - phdr.p_filesz > 0) { @@ -620,7 +621,8 @@ namespace Driver delete Drv.DeviceOperations; /* Reload the driver */ - FileNode *drvNode = fs->GetByPath(Drv.Path.c_str(), nullptr); + Node root = fs->GetRoot(0); + Node drvNode = fs->Lookup(root, Drv.Path); if (!drvNode) { error("Failed to open driver file %s", Drv.Path.c_str()); @@ -684,7 +686,7 @@ namespace Driver newDrvObj.Initialized = true; } - Manager::Manager() { this->InitializeDaemonFS(); } + Manager::Manager() { this->InitializeDeviceDirectory(); } Manager::~Manager() { diff --git a/Kernel/core/driver/manager.cpp b/Kernel/core/driver/manager.cpp new file mode 100644 index 00000000..1b59d3e7 --- /dev/null +++ b/Kernel/core/driver/manager.cpp @@ -0,0 +1,256 @@ +/* + 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 + +#include "../../kernel.h" + +using namespace vfs; + +namespace Driver +{ + 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: + { + std::string prefix = "event"; + for (size_t j = 0; j < 128; j++) + { + std::string deviceName = prefix + std::to_string(j); + Node node = fs->Lookup(devInputNode, deviceName); + if (node) + continue; + + /* c rwx r-- r-- */ + mode_t mode = S_IRWXU | + S_IRGRP | + S_IROTH | + S_IFCHR; + + node = fs->Create(devInputNode, deviceName, mode); + node->inode->SetDevice(DriverID, i); + + DriverHandlers dh{}; + dh.Ops = Operations; + dh.Node = node->inode; + dh.InputReports = new RingBuffer(16); + dop->insert({i, std::move(dh)}); + return i; + } + + ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID); + } + default: + ReturnLogError(-EINVAL, "Invalid device type %d", Type); + } + } + + ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID); + } + + dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, 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); + if (dOps != dop->end()) + continue; + + eNode node = fs->Lookup(devNode, name); + if (node == true) + ReturnLogError(-EEXIST, "Device file %s already exists", name); + + node = fs->Create(devNode, name, mode); + if (node == false) + ReturnLogError(-node.Error, "Failed to create device file %s; %s", name, node.what()); + + node.Value->inode->SetDevice(DriverID, i); + + DriverHandlers dh{}; + dh.Ops = Operations; + dh.Node = node.Value->inode; + dh.InputReports = new RingBuffer(16); + dop->insert({i, std::move(dh)}); + return i; + } + + ReturnLogError(-EOVERFLOW, "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; + } + + dev_t Manager::RegisterBlockDevice(dev_t DriverID, struct BlockDevice *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; + std::string prefix = Device->Name; + for (size_t j = 0; j < 128; j++) + { + std::string deviceName = prefix + std::to_string(j); + Node node = fs->Lookup(devBlockNode, deviceName); + if (node) + continue; + debug("Creating \"%s\"", deviceName.c_str()); + + /* b rwx --- --- */ + mode_t mode = S_IRWXU | + S_IFBLK; + + node = fs->Create(devBlockNode, deviceName, mode); + node->inode->SetDevice(DriverID, j); + auto devNode = (Manager::DeviceInode *)node->inode; + devNode->Size = Device->Size; + devNode->BlockSize = Device->BlockSize; + devNode->Blocks = Device->BlockCount; + devNode->inode.PrivateData = Device->PrivateData; + + DriverHandlers dh{}; + dh.Ops = Device->Ops; + dh.Node = node->inode; + dop->insert({j, std::move(dh)}); + debug("dh ops:%#lx node:%#lx %d", dh.Ops, dh.Node, j); + return j; + } + + ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID); + } + + int Manager::UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID) + { + 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(DeviceID); + if (dOps == dop->end()) + ReturnLogError(-EINVAL, "Device %d not found", DeviceID); + dop->erase(dOps); + return 0; + } + + void *Manager::AllocateMemory(dev_t DriverID, size_t Pages) + { + 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 Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages) + { + auto itr = Drivers.find(DriverID); + assert(itr != Drivers.end()); + itr->second.vma->FreePages(Pointer, Pages); + } + + 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; + } +} diff --git a/Kernel/core/memory/page_table.cpp b/Kernel/core/memory/page_table.cpp index d4ab3d7f..9473e97b 100644 --- a/Kernel/core/memory/page_table.cpp +++ b/Kernel/core/memory/page_table.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include diff --git a/Kernel/core/panic/diag.cpp b/Kernel/core/panic/diag.cpp index 6c237dcb..bfe55506 100644 --- a/Kernel/core/panic/diag.cpp +++ b/Kernel/core/panic/diag.cpp @@ -64,7 +64,7 @@ struct DiagnosticFile } Data; }; -nsa bool WriteDiagDataToNode(FileNode *node) +nsa bool WriteDiagDataToNode(Node node) { uintptr_t KStart = (uintptr_t)&_kernel_start; uintptr_t kEnd = (uintptr_t)&_kernel_end; @@ -89,7 +89,7 @@ nsa bool WriteDiagDataToNode(FileNode *node) memcpy(file->Data.KernelMemory, (void *)KStart, kSize); ExPrint("Writing to %s\n", node->Path.c_str()); - size_t w = node->Write(buf, fileSize, 0); + size_t w = fs->Write(node, buf, fileSize, 0); if (w != fileSize) { debug("%d out of %d bytes written", w, fileSize); @@ -115,7 +115,8 @@ nsa void DiagnosticDataCollection() S_IROTH | S_IFDIR; - FileNode *panicDir = fs->ForceCreate(nullptr, "/sys/log/panic", mode); + Node root = fs->GetRoot(0); + Node panicDir = fs->Create(root, "/sys/log/panic", mode); if (!panicDir) { ExPrint("\x1b[0;30;41mFailed to create /sys/log/panic\x1b[0m\n"); @@ -123,14 +124,14 @@ nsa void DiagnosticDataCollection() return; } - FileNode *dumpFile; + Node dumpFile; Time::Clock clock = Time::ReadClock(); char filename[64]; for (int i = 0; i < INT32_MAX; i++) { sprintf(filename, "dump-%d-%d-%d-%d.dmp", clock.Year, clock.Month, clock.Day, i); - if (fs->PathExists(filename, panicDir)) + if (fs->Lookup(panicDir, filename)) continue; mode = S_IRWXU | diff --git a/Kernel/core/panic/handler.cpp b/Kernel/core/panic/handler.cpp index 8f19590d..385e773b 100644 --- a/Kernel/core/panic/handler.cpp +++ b/Kernel/core/panic/handler.cpp @@ -408,8 +408,7 @@ nsa __noreturn void HandleBufferOverflow() CPU::Stop(); } -EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line, - const char *Expression) +EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line, const char *Expression) { DisplayAssertionFailed(File, Line, Expression); CPU::Stop(); diff --git a/Kernel/include/filesystem/ext2.hpp b/Kernel/drivers/fs/ext2/ext2.hpp similarity index 97% rename from Kernel/include/filesystem/ext2.hpp rename to Kernel/drivers/fs/ext2/ext2.hpp index 830abe6e..6c21f17e 100644 --- a/Kernel/include/filesystem/ext2.hpp +++ b/Kernel/drivers/fs/ext2/ext2.hpp @@ -20,9 +20,9 @@ #include -#include +#include -namespace vfs +namespace Driver::ExtendedFilesystem { class EXT2 { diff --git a/Kernel/drivers/fs/ustar/ustar.cpp b/Kernel/drivers/fs/ustar/ustar.cpp new file mode 100644 index 00000000..b71120a2 --- /dev/null +++ b/Kernel/drivers/fs/ustar/ustar.cpp @@ -0,0 +1,200 @@ +/* + 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 + +using namespace vfs; + +namespace Driver::UnixStandardTAR +{ + dev_t DriverID; + + int USTAR_AllocateInode(FileSystemInfo *Info, Inode **Result) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_DeleteInode(FileSystemInfo *Info, Inode *Node) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Synchronize(FileSystemInfo *Info, Inode *Node) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Destroy(FileSystemInfo *Info) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Probe(void *Device) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Mount(FileSystemInfo *FS, Inode **Root, void *Device) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Unmount(FileSystemInfo *FS) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Lookup(Inode *Parent, const char *Name, Inode **Result) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Create(Inode *Parent, const char *Name, mode_t Mode, Inode **Result) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Remove(Inode *Parent, const char *Name) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Rename(Inode *Parent, const char *OldName, const char *NewName) + { + assert(!"NOT IMPLEMENTED"); + } + + ssize_t USTAR_Read(Inode *Node, void *Buffer, size_t Size, off_t Offset) + { + assert(!"NOT IMPLEMENTED"); + } + + ssize_t USTAR_Write(Inode *Node, const void *Buffer, size_t Size, off_t Offset) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Truncate(Inode *Node, off_t Size) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Open(Inode *Node, int Flags, mode_t Mode) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Close(Inode *Node) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Ioctl(Inode *Node, unsigned long Request, void *Argp) + { + assert(!"NOT IMPLEMENTED"); + } + + ssize_t USTAR_ReadDir(Inode *Node, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_MkDir(Inode *Parent, const char *Name, mode_t Mode, Inode **Result) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_RmDir(Inode *Parent, const char *Name) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result) + { + assert(!"NOT IMPLEMENTED"); + } + + ssize_t USTAR_ReadLink(Inode *Node, char *Buffer, size_t Size) + { + assert(!"NOT IMPLEMENTED"); + } + + off_t USTAR_Seek(Inode *Node, off_t Offset) + { + assert(!"NOT IMPLEMENTED"); + } + + int USTAR_Stat(Inode *Node, kstat *Stat) + { + assert(!"NOT IMPLEMENTED"); + } + + static SuperBlockOperations ustarSuperOps = { + .AllocateInode = USTAR_AllocateInode, + .DeleteInode = USTAR_DeleteInode, + .Synchronize = USTAR_Synchronize, + .Destroy = USTAR_Destroy, + .Probe = USTAR_Probe, + .Mount = USTAR_Mount, + .Unmount = USTAR_Unmount}; + + static InodeOperations ustarInodeOps = { + .Lookup = USTAR_Lookup, + .Create = USTAR_Create, + .Remove = USTAR_Remove, + .Rename = USTAR_Rename, + .Read = USTAR_Read, + .Write = USTAR_Write, + .Truncate = USTAR_Truncate, + .Open = USTAR_Open, + .Close = USTAR_Close, + .Ioctl = USTAR_Ioctl, + .ReadDir = USTAR_ReadDir, + .MkDir = USTAR_MkDir, + .RmDir = USTAR_RmDir, + .SymLink = USTAR_SymLink, + .ReadLink = USTAR_ReadLink, + .Seek = USTAR_Seek, + .Stat = USTAR_Stat}; + + int Entry() + { + FileSystemInfo *fsi = new FileSystemInfo; + fsi->Name = "Unix Standard TAR"; + fsi->SuperOps = ustarSuperOps; + fsi->Ops = ustarInodeOps; + v0::RegisterFileSystem(DriverID, fsi); + return 0; + } + + int Final() { return 0; } + int Panic() { return 0; } + int Probe() { return 0; } + + REGISTER_BUILTIN_DRIVER(ustar, + "Unix Standard TAR Driver", + "enderice2", + 1, 0, 0, + Entry, + Final, + Panic, + Probe); +} diff --git a/Kernel/drivers/storage/ahci/ahci.cpp b/Kernel/drivers/storage/ahci/ahci.cpp index cb887914..6c7132a8 100644 --- a/Kernel/drivers/storage/ahci/ahci.cpp +++ b/Kernel/drivers/storage/ahci/ahci.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -572,6 +573,9 @@ namespace Driver::AHCI HBAPort *HBAPortPtr; uint8_t *Buffer; uint8_t PortNumber; + uint32_t BlockSize; + uint32_t BlockCount; + size_t Size; ATA_IDENTIFY *IdentifyData; Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber) @@ -614,6 +618,7 @@ namespace Driver::AHCI void Configure() { + debug("Configuring port %d", PortNumber); this->StopCMD(); void *CmdBase = v0::AllocateMemory(DriverID, 1); HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase; @@ -639,19 +644,35 @@ namespace Driver::AHCI Identify(); + if (IdentifyData->CommandSetSupport.BigLba) + { + if ((IdentifyData->CommandSetActive.Words119_120Valid & 0x1) != 0) + { + uint32_t wordsPerLogicalSector = (IdentifyData->WordsPerLogicalSector[1] << 16) | IdentifyData->WordsPerLogicalSector[0]; + if (wordsPerLogicalSector != 0) + this->BlockSize = wordsPerLogicalSector * 2; + } + } + this->BlockSize = 512; + + this->BlockCount = this->IdentifyData->UserAddressableSectors; + this->Size = this->BlockCount * this->BlockSize; + trace("Port %d \"%x %x %x %x\" configured", PortNumber, HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1], HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]); } - bool ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write) + int ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write) { if (this->AHCIPortType == PortType::SATAPI && Write == true) { trace("SATAPI port does not support write."); - return false; + return ENOTSUP; } + debug("%s op on port %d, sector %d, count %d", Write ? "Write" : "Read", this->PortNumber, Sector, SectorCount); + uint32_t SectorL = (uint32_t)Sector; uint32_t SectorH = (uint32_t)(Sector >> 32); @@ -706,7 +727,7 @@ namespace Driver::AHCI if (spinLock == 1000000) { trace("Port not responding."); - return false; + return ETIMEDOUT; } HBAPortPtr->CommandIssue = 1; @@ -723,7 +744,7 @@ namespace Driver::AHCI spinLock = 0; retries++; if (retries > 10) - return false; + return ETIMEDOUT; } if (HBAPortPtr->CommandIssue == 0) @@ -733,11 +754,11 @@ namespace Driver::AHCI if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES) { trace("Error reading/writing (%d).", Write); - return false; + return EIO; } } - return true; + return 0; } void Identify() @@ -840,34 +861,61 @@ namespace Driver::AHCI } } - int Open(struct Inode *, int, mode_t) - { - return 0; - } - - int Close(struct Inode *) - { - return 0; - } - ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) { - uint64_t sector = Offset / 512; - uint32_t sectorCount = uint32_t(Size / 512); - int num = Node->GetMinor(); - bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, Buffer, false); - return ok ? Size : 0; + Port *port = static_cast(Node->PrivateData); + if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0) + { + trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize); + return -EINVAL; + } + + uint64_t sector = Offset / port->BlockSize; + uint32_t sectorCount = uint32_t(Size / port->BlockSize); + if (sectorCount == 0) + { + trace("Attempt to read 0 sectors"); + return 0; + } + + bool status = port->ReadWrite(sector, sectorCount, Buffer, false); + if (status != 0) + { + trace("Error '%s' reading from port %d", strerror(status), port->PortNumber); + return status; + } + return Size; } ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) { - uint64_t sector = Offset / 512; - uint32_t sectorCount = uint32_t(Size / 512); - int num = Node->GetMinor(); - bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, (void *)Buffer, true); - return ok ? Size : 0; + Port *port = static_cast(Node->PrivateData); + if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0) + { + trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize); + return -EINVAL; + } + + uint64_t sector = Offset / port->BlockSize; + uint32_t sectorCount = uint32_t(Size / port->BlockSize); + if (sectorCount == 0) + { + trace("Attempt to write 0 sectors"); + return 0; + } + + bool status = port->ReadWrite(sector, sectorCount, (void *)Buffer, true); + if (status != 0) + { + trace("Error '%s' writing to port %d", strerror(status), port->PortNumber); + return status; + } + return Size; } + int Open(struct Inode *, int, mode_t) { return 0; } + int Close(struct Inode *) { return 0; } + const struct InodeOperations ops = { .Lookup = nullptr, .Create = nullptr, @@ -915,8 +963,18 @@ namespace Driver::AHCI { KPrint("%s drive found at port %d", PortTypeName[portType], i); Port *port = new Port(portType, &hba->Ports[i], i); - dev_t ret = v0::RegisterDevice(DriverID, BLOCK_TYPE_HDD, &ops); + port->Configure(); + + BlockDevice *dev = new BlockDevice; + dev->Name = "ahci"; + dev->BlockSize = port->BlockSize; + dev->BlockCount = port->BlockCount; + dev->Size = port->Size; + dev->Ops = &ops; + dev->PrivateData = port; + dev_t ret = v0::RegisterBlockDevice(DriverID, dev); PortDevices[ret] = port; + debug("Port %d \"%s\" registered as %d", i, port->IdentifyData->ModelNumber, ret); break; } case PortType::SEMB: @@ -942,10 +1000,6 @@ namespace Driver::AHCI return -ENODEV; } - trace("Initializing AHCI ports"); - for (auto &&p : PortDevices) - p.second->Configure(); - /* We don't use the interrupt handler now... maybe we will in the future */ // RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived); @@ -957,7 +1011,7 @@ namespace Driver::AHCI for (auto &&p : PortDevices) { p.second->StopCMD(); - v0::UnregisterDevice(DriverID, p.first); + v0::UnregisterBlockDevice(DriverID, p.first); delete p.second; } diff --git a/Kernel/exec/binary_parse.cpp b/Kernel/exec/binary_parse.cpp index a0c6c295..9af1cdda 100644 --- a/Kernel/exec/binary_parse.cpp +++ b/Kernel/exec/binary_parse.cpp @@ -25,7 +25,7 @@ namespace Execute { - BinaryType GetBinaryType(FileNode *Node) + BinaryType GetBinaryType(Node &Node) { debug("Checking binary type of %s", Node->Path.c_str()); BinaryType type; @@ -34,13 +34,13 @@ namespace Execute ReturnLogError((BinaryType)-ENOENT, "Node is null"); Elf_Ehdr ehdr; - Node->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(Node, &ehdr, sizeof(Elf_Ehdr), 0); mach_header mach; - Node->Read(&mach, sizeof(mach_header), 0); + fs->Read(Node, &mach, sizeof(mach_header), 0); IMAGE_DOS_HEADER mz; - Node->Read(&mz, sizeof(IMAGE_DOS_HEADER), 0); + fs->Read(Node, &mz, sizeof(IMAGE_DOS_HEADER), 0); /* Check ELF header. */ if (ehdr.e_ident[EI_MAG0] == ELFMAG0 && @@ -64,10 +64,10 @@ namespace Execute else if (mz.e_magic == IMAGE_DOS_SIGNATURE) { IMAGE_NT_HEADERS pe; - Node->Read(&pe, sizeof(IMAGE_NT_HEADERS), mz.e_lfanew); + fs->Read(Node, &pe, sizeof(IMAGE_NT_HEADERS), mz.e_lfanew); IMAGE_OS2_HEADER ne; - Node->Read(&ne, sizeof(IMAGE_OS2_HEADER), mz.e_lfanew); + fs->Read(Node, &ne, sizeof(IMAGE_OS2_HEADER), mz.e_lfanew); /* TODO: LE, EDOS */ if (pe.Signature == IMAGE_NT_SIGNATURE) @@ -99,14 +99,14 @@ namespace Execute BinaryType GetBinaryType(std::string Path) { - FileNode *node = fs->GetByPath(Path.c_str(), nullptr); + Node node = fs->Lookup(thisProcess->Info.RootNode, Path); if (node->IsSymbolicLink()) { char buffer[512]; - node->ReadLink(buffer, sizeof(buffer)); - node = fs->GetByPath(buffer, node->Parent); + fs->ReadLink(node, buffer, sizeof(buffer)); + node = fs->Lookup(node->Parent, buffer); } - debug("Checking binary type of %s (returning %p)", Path.c_str(), node); + debug("Checking binary type of %s (returning %p)", Path.c_str(), node.get()); assert(node != nullptr); return GetBinaryType(node); } diff --git a/Kernel/exec/elf/elf_loader.cpp b/Kernel/exec/elf/elf_loader.cpp index d042dcc9..f55930d6 100644 --- a/Kernel/exec/elf/elf_loader.cpp +++ b/Kernel/exec/elf/elf_loader.cpp @@ -32,7 +32,7 @@ using namespace vfs; namespace Execute { - void ELFObject::GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma, FileNode *fd, Elf_Ehdr ELFHeader, uintptr_t EntryPoint, uintptr_t BaseAddress) + void ELFObject::GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma, Node &fd, Elf_Ehdr ELFHeader, uintptr_t EntryPoint, uintptr_t BaseAddress) { char *aux_platform = (char *)vma->RequestPages(1, true); /* TODO: 4KiB is too much for this */ strcpy(aux_platform, "x86_64"); @@ -79,7 +79,7 @@ namespace Execute #endif } - void ELFObject::LoadSegments(FileNode *fd, PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress) + void ELFObject::LoadSegments(Node &fd, PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress) { Memory::Virtual vmm(TargetProcess->PageTable); Memory::VirtualMemoryArea *vma = TargetProcess->vma; @@ -91,7 +91,7 @@ namespace Execute size_t SegmentsSize = 0; for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) { - fd->Read(&ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); + fs->Read(fd, &ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); if (ProgramHeader.p_type == PT_LOAD || ProgramHeader.p_type == PT_DYNAMIC) { @@ -113,7 +113,7 @@ namespace Execute for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) { - fd->Read(&ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); + fs->Read(fd, &ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); switch (ProgramHeader.p_type) { @@ -132,7 +132,7 @@ namespace Execute if (ProgramHeader.p_filesz > 0) { - fd->Read(SegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); + fs->Read(fd, (void *)SegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -158,7 +158,7 @@ namespace Execute if (ProgramHeader.p_filesz > 0) { - fd->Read(DynamicSegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); + fs->Read(fd, (void *)DynamicSegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -212,7 +212,7 @@ namespace Execute { for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) { - fd->Read(&ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); + fs->Read(fd, &ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); switch (ProgramHeader.p_type) { case PT_LOAD: @@ -245,7 +245,7 @@ namespace Execute if (ProgramHeader.p_filesz > 0) { debug("%d %#lx %d", ProgramHeader.p_offset, (uint8_t *)pAddr + destOffset, ProgramHeader.p_filesz); - fd->Read((uint8_t *)pAddr + destOffset, ProgramHeader.p_filesz, ProgramHeader.p_offset); + fs->Read(fd, (uint8_t *)pAddr + destOffset, ProgramHeader.p_filesz, ProgramHeader.p_offset); } if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) @@ -265,35 +265,35 @@ namespace Execute case PT_NOTE: { Elf_Nhdr NoteHeader; - fd->Read(&NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset); + fs->Read(fd, &NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset); switch (NoteHeader.n_type) { case NT_PRSTATUS: { Elf_Prstatus prstatus; - fd->Read(&prstatus, sizeof(Elf_Prstatus), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); + fs->Read(fd, &prstatus, sizeof(Elf_Prstatus), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); debug("PRSTATUS: %#lx", prstatus.pr_reg[0]); break; } case NT_PRPSINFO: { Elf_Prpsinfo prpsinfo; - fd->Read(&prpsinfo, sizeof(Elf_Prpsinfo), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); + fs->Read(fd, &prpsinfo, sizeof(Elf_Prpsinfo), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); debug("PRPSINFO: %s", prpsinfo.pr_fname); break; } case NT_PLATFORM: { char platform[256]; - fd->Read(&platform, sizeof(platform), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); + fs->Read(fd, &platform, sizeof(platform), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); debug("PLATFORM: %s", platform); break; } case NT_AUXV: { Elf_auxv_t auxv; - fd->Read(&auxv, sizeof(Elf_auxv_t), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); + fs->Read(fd, &auxv, sizeof(Elf_auxv_t), ProgramHeader.p_offset + sizeof(Elf_Nhdr)); debug("AUXV: %#lx", auxv.a_un.a_val); break; } @@ -311,7 +311,7 @@ namespace Execute debug("TLS Size: %ld (%ld pages)", tlsSize, TO_PAGES(tlsSize)); void *tlsMemory = vma->RequestPages(TO_PAGES(tlsSize)); - fd->Read(tlsMemory, tlsSize, ProgramHeader.p_offset); + fs->Read(fd, tlsMemory, tlsSize, ProgramHeader.p_offset); TargetProcess->TLS = { .pBase = uintptr_t(tlsMemory), .vBase = ProgramHeader.p_vaddr, @@ -346,12 +346,12 @@ namespace Execute case PT_GNU_PROPERTY: { Elf_Nhdr NoteHeader; - fd->Read(&NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset); + fs->Read(fd, &NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset); if (NoteHeader.n_type == NT_GNU_PROPERTY_TYPE_0) { char noteName[0x400]; - fd->Read(noteName, NoteHeader.n_namesz, ProgramHeader.p_offset + sizeof(Elf_Nhdr)); + fs->Read(fd, noteName, NoteHeader.n_namesz, ProgramHeader.p_offset + sizeof(Elf_Nhdr)); noteName[NoteHeader.n_namesz - 1] = '\0'; if (strcmp(noteName, "GNU") == 0) @@ -394,10 +394,10 @@ namespace Execute TargetProcess->ProgramBreak->InitBrk(ProgramBreak); } - void ELFObject::LoadExec(FileNode *fd, PCB *TargetProcess) + void ELFObject::LoadExec(Node &fd, PCB *TargetProcess) { Elf_Ehdr ehdr{}; - fd->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0); uintptr_t entry = ehdr.e_entry; debug("Entry point is %#lx", entry); @@ -424,10 +424,10 @@ namespace Execute #endif } - void ELFObject::LoadDyn(FileNode *fd, PCB *TargetProcess) + void ELFObject::LoadDyn(Node &fd, PCB *TargetProcess) { Elf_Ehdr ehdr{}; - fd->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0); uintptr_t entry = ehdr.e_entry; debug("Entry point is %#lx", entry); @@ -465,24 +465,25 @@ namespace Execute Elf_Phdr interp = interpVec.front(); std::string interpreterPath; interpreterPath.resize(256); - fd->Read(interpreterPath.data(), 256, interp.p_offset); + fs->Read(fd, interpreterPath.data(), 256, interp.p_offset); debug("Interpreter: %s", interpreterPath.c_str()); - FileNode *ifd = fs->GetByPath(interpreterPath.c_str(), TargetProcess->Info.RootNode); - if (ifd == nullptr) + eNode ret = fs->Lookup(TargetProcess->Info.RootNode, interpreterPath); + if (ret == false) { - warn("Failed to open interpreter file: %s", interpreterPath.c_str()); + warn("Failed to open interpreter file: %s", ret.what()); return; } + Node ifd = ret; if (ifd->IsSymbolicLink()) { char buffer[512]; - ifd->ReadLink(buffer, sizeof(buffer)); - ifd = fs->GetByPath(buffer, ifd->Parent); + fs->ReadLink(ifd, buffer, sizeof(buffer)); + ifd = fs->Lookup(ifd->Parent, buffer); } - debug("ifd: %p, interpreter: %s", ifd, interpreterPath.c_str()); + debug("ifd: %p, interpreter: %s", ifd.get(), interpreterPath.c_str()); if (GetBinaryType(interpreterPath) != BinTypeELF) { warn("Interpreter %s is not an ELF file", interpreterPath.c_str()); @@ -492,10 +493,10 @@ namespace Execute LoadInterpreter(ifd, TargetProcess); } - bool ELFObject::LoadInterpreter(FileNode *fd, PCB *TargetProcess) + bool ELFObject::LoadInterpreter(Node &fd, PCB *TargetProcess) { Elf_Ehdr ehdr; - fd->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0); switch (ehdr.e_type) { @@ -550,18 +551,19 @@ namespace Execute return; } - FileNode *fd = fs->GetByPath(AbsolutePath.c_str(), TargetProcess->Info.RootNode); - if (fd == nullptr) + eNode ret = fs->Lookup(TargetProcess->Info.RootNode, AbsolutePath); + if (ret == false) { - error("Failed to open %s, errno: %d", AbsolutePath.c_str(), fd); + error("Failed to open %s, errno: %s", AbsolutePath.c_str(), ret.what()); return; } + Node fd = ret; if (fd->IsSymbolicLink()) { char buffer[512]; - fd->ReadLink(buffer, sizeof(buffer)); - fd = fs->GetByPath(buffer, fd->Parent); + fs->ReadLink(fd, buffer, sizeof(buffer)); + fd = fs->Lookup(fd->Parent, buffer); } debug("Opened %s", AbsolutePath.c_str()); @@ -575,7 +577,7 @@ namespace Execute envc++; Elf_Ehdr ehdr{}; - fd->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0); // ELFargv = new const char *[argc + 2]; size_t argv_size = argc + 2 * sizeof(char *); diff --git a/Kernel/exec/elf/elf_parse.cpp b/Kernel/exec/elf/elf_parse.cpp index 14215129..4e644877 100644 --- a/Kernel/exec/elf/elf_parse.cpp +++ b/Kernel/exec/elf/elf_parse.cpp @@ -92,10 +92,10 @@ namespace Execute return nullptr; } - Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name) + Elf_Sym ELFLookupSymbol(Node fd, std::string Name) { Elf_Ehdr ehdr{}; - fd->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0); Elf_Shdr symTable{}; Elf_Shdr stringTable{}; @@ -103,13 +103,13 @@ namespace Execute for (Elf64_Half i = 0; i < ehdr.e_shnum; i++) { Elf_Shdr shdr; - fd->Read(&shdr, sizeof(Elf_Shdr), ehdr.e_shoff + (i * sizeof(Elf_Shdr))); + fs->Read(fd, &shdr, sizeof(Elf_Shdr), ehdr.e_shoff + (i * sizeof(Elf_Shdr))); switch (shdr.sh_type) { case SHT_SYMTAB: symTable = shdr; - fd->Read(&stringTable, sizeof(Elf_Shdr), ehdr.e_shoff + (shdr.sh_link * sizeof(Elf_Shdr))); + fs->Read(fd, &stringTable, sizeof(Elf_Shdr), ehdr.e_shoff + (shdr.sh_link * sizeof(Elf_Shdr))); break; default: break; @@ -126,11 +126,11 @@ namespace Execute { // Elf_Sym *sym = (Elf_Sym *)((uintptr_t)Header + symTable->sh_offset + (i * sizeof(Elf_Sym))); Elf_Sym sym; - fd->Read(&sym, sizeof(Elf_Sym), symTable.sh_offset + (i * sizeof(Elf_Sym))); + fs->Read(fd, &sym, sizeof(Elf_Sym), symTable.sh_offset + (i * sizeof(Elf_Sym))); // char *str = (char *)((uintptr_t)Header + stringTable->sh_offset + sym->st_name); char str[256]; - fd->Read(&str, sizeof(str), stringTable.sh_offset + sym.st_name); + fs->Read(fd, &str, sizeof(str), stringTable.sh_offset + sym.st_name); if (strcmp(str, Name.c_str()) == 0) return sym; diff --git a/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp b/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp index dd07f398..c7474c2b 100644 --- a/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp +++ b/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp @@ -21,7 +21,7 @@ namespace Execute { - std::vector ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag) + std::vector ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag) { std::vector ret; std::vector phdrs = ELFGetSymbolType(fd, PT_DYNAMIC); @@ -37,7 +37,7 @@ namespace Execute Elf_Dyn dyn; for (size_t i = 0; i < phdr.p_filesz / sizeof(Elf_Dyn); i++) { - fd->Read(&dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn))); + fs->Read(fd, &dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn))); if (dyn.d_tag != Tag) continue; diff --git a/Kernel/exec/elf/parse/elf_get_sections.cpp b/Kernel/exec/elf/parse/elf_get_sections.cpp index 363028c2..e1367cf0 100644 --- a/Kernel/exec/elf/parse/elf_get_sections.cpp +++ b/Kernel/exec/elf/parse/elf_get_sections.cpp @@ -21,18 +21,18 @@ namespace Execute { - std::vector ELFGetSections(FileNode *fd, const char *SectionName) + std::vector ELFGetSections(Node fd, const char *SectionName) { std::vector ret; Elf_Ehdr ehdr; - fd->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0); std::unique_ptr sections(new Elf_Shdr[ehdr.e_shnum]); - fd->Read(sections.get(), sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff); + fs->Read(fd, sections.get(), sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff); std::string sectionNames(sections[ehdr.e_shstrndx].sh_size, '\0'); - fd->Read(sectionNames.data(), sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset); + fs->Read(fd, sectionNames.data(), sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset); for (Elf_Half i = 0; i < ehdr.e_shnum; ++i) { diff --git a/Kernel/exec/elf/parse/elf_get_symbol_type.cpp b/Kernel/exec/elf/parse/elf_get_symbol_type.cpp index 5e22d84a..a495e41f 100644 --- a/Kernel/exec/elf/parse/elf_get_symbol_type.cpp +++ b/Kernel/exec/elf/parse/elf_get_symbol_type.cpp @@ -21,15 +21,15 @@ namespace Execute { - std::vector ELFGetSymbolType(FileNode *fd, SegmentTypes Tag) + std::vector ELFGetSymbolType(Node &fd, SegmentTypes Tag) { std::vector ret; Elf_Ehdr ehdr; - fd->Read(&ehdr, sizeof(Elf_Ehdr), 0); + fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0); Elf_Phdr phdr; - fd->Read(&phdr, sizeof(Elf_Phdr), ehdr.e_phoff); + fs->Read(fd, &phdr, sizeof(Elf_Phdr), ehdr.e_phoff); off_t off = ehdr.e_phoff; for (Elf_Half i = 0; i < ehdr.e_phnum; i++) @@ -38,7 +38,7 @@ namespace Execute ret.push_back(phdr); off += sizeof(Elf_Phdr); - fd->Read(&phdr, sizeof(Elf_Phdr), off); + fs->Read(fd, &phdr, sizeof(Elf_Phdr), off); } return ret; diff --git a/Kernel/exec/spawn.cpp b/Kernel/exec/spawn.cpp index 9ffb3a43..60a89a81 100644 --- a/Kernel/exec/spawn.cpp +++ b/Kernel/exec/spawn.cpp @@ -35,7 +35,13 @@ namespace Execute Tasking::TaskCompatibility Compatibility, bool Critical) { - FileNode *fd = fs->GetByPath(Path, nullptr); + if (Parent == nullptr) + { + debug("no parent specified, using current process"); + Parent = thisProcess; + } + + Node fd = fs->Lookup(Parent->Info.RootNode, Path); if (fd == nullptr) return -ENOENT; @@ -44,8 +50,8 @@ namespace Execute if (fd->IsSymbolicLink()) { char buffer[512]; - fd->ReadLink(buffer, sizeof(buffer)); - fd = fs->GetByPath(buffer, fd->Parent); + fs->ReadLink(fd, buffer, sizeof(buffer)); + fd = fs->Lookup(fd->Parent, buffer); if (fd == nullptr) return -ENOENT; } @@ -61,7 +67,7 @@ namespace Execute const char *BaseName; cwk_path_get_basename(Path, &BaseName, nullptr); Elf32_Ehdr ELFHeader; - fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0); + fs->Read(fd, &ELFHeader, sizeof(Elf32_Ehdr), 0); switch (ELFHeader.e_machine) { @@ -108,7 +114,6 @@ namespace Execute PCB *Process; if (Fork) { - assert(Parent != nullptr); CriticalSection cs; Process = Parent; @@ -124,17 +129,13 @@ namespace Execute } else { - if (Parent == nullptr) - Parent = thisProcess; - - Process = TaskManager->CreateProcess(Parent, BaseName, - TaskExecutionMode::User, - false, 0, 0); + Process = TaskManager->CreateProcess(Parent, BaseName, User, false, 0, 0); Process->Info.Compatibility = Compatibility; Process->Info.Architecture = Arch; } - Process->SetWorkingDirectory(fs->GetByPath(Path, nullptr)->Parent); + Node cwdNode = fs->Lookup(Parent->Info.RootNode, Path); + Process->SetWorkingDirectory(fs->Convert(cwdNode->Parent)); Process->SetExe(Path); ELFObject *obj = new ELFObject(Path, Process, argv, envp); @@ -148,9 +149,9 @@ namespace Execute vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors; vfs::FileDescriptorTable *fdt = Process->FileDescriptors; - auto ForkStdio = [pfdt, fdt](FileNode *SearchNode) + auto ForkStdio = [pfdt, fdt](Node SearchNode) { - if (unlikely(SearchNode == nullptr)) + if (unlikely(SearchNode.get() == nullptr)) return false; for (const auto &ffd : pfdt->FileMap) @@ -158,12 +159,11 @@ namespace Execute if (ffd.second.Flags & O_CLOEXEC) continue; - if (ffd.second.Node == SearchNode) - { - fdt->usr_open(ffd.second.Node->Path.c_str(), - ffd.second.Flags, ffd.second.Mode); - return true; - } + if (ffd.second.node.get() != SearchNode.get()) + continue; + + fdt->usr_open(ffd.second.node->Path.c_str(), ffd.second.Flags, ffd.second.Mode); + return true; } return false; }; diff --git a/Kernel/storage/descriptor.cpp b/Kernel/fs/descriptor.cpp similarity index 73% rename from Kernel/storage/descriptor.cpp rename to Kernel/fs/descriptor.cpp index a0e7b0d5..5ca4990c 100644 --- a/Kernel/storage/descriptor.cpp +++ b/Kernel/fs/descriptor.cpp @@ -15,7 +15,7 @@ along with Fennix Kernel. If not, see . */ -#include +#include #include #include @@ -47,8 +47,7 @@ namespace vfs return 0; } - int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath, - mode_t Mode, int Flags) + int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags) { Tasking::PCB *pcb = thisProcess; @@ -77,8 +76,7 @@ namespace vfs if (Flags & O_RDWR) { - if (!(Mode & S_IRUSR) || - !(Mode & S_IWUSR)) + if (!(Mode & S_IRUSR) || !(Mode & S_IWUSR)) { debug("No read/write permission (%d)", Mode); return -EACCES; @@ -95,12 +93,11 @@ namespace vfs if (Flags & O_CREAT) { - FileNode *ret = fs->Create(pcb->CWD, AbsolutePath, Mode); - if (Flags & O_EXCL && ret == nullptr) + eNode ret = fs->Create(pcb->CWD, AbsolutePath, Mode); + if (Flags & O_EXCL && ret == false) { - debug("%s: File already exists?, returning EEXIST", - AbsolutePath); - return -EEXIST; + debug("%s: File already exists?, returning %s", AbsolutePath, ret.what()); + return -ret.Error; } } @@ -109,18 +106,18 @@ namespace vfs fixme("O_CLOEXEC"); } - FileNode *File = fs->GetByPath(AbsolutePath, pcb->CWD); - - if (!File) + eNode ret = fs->Lookup(pcb->CWD, AbsolutePath); + if (ret == false) { - error("Failed to open file %s", AbsolutePath); - return -ENOENT; + error("Failed to open file %s, %s", AbsolutePath, ret.what()); + return -ret.Error; } + Node node = ret; if (Flags & O_TRUNC) { debug("Truncating file %s", AbsolutePath); - File->Truncate(0); + fs->Truncate(node, 0); } Fildes fd{}; @@ -129,13 +126,13 @@ namespace vfs { debug("Appending to file %s", AbsolutePath); struct kstat stat; - File->Stat(&stat); - fd.Offset = File->Seek(stat.Size); + fs->Stat(node, &stat); + fd.Offset = fs->Seek(node, stat.Size); } fd.Mode = Mode; fd.Flags = Flags; - fd.Node = File; + fd.node = node; int fdn = this->GetFreeFileDescriptor(); if (fdn < 0) @@ -145,9 +142,8 @@ namespace vfs char linkName[64]; snprintf(linkName, 64, "%d", fdn); - assert(fs->CreateLink(linkName, this->fdDir, AbsolutePath) != nullptr); - - File->Open(Flags, Mode); + assert(fs->CreateLink(this->fdDir, linkName, AbsolutePath) == true); + fs->Open(node, Flags, Mode); return fdn; } @@ -157,7 +153,7 @@ namespace vfs if (it == this->FileMap.end()) ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor); - fs->Remove(it->second.Node); + fs->Remove(it->second.node); this->FileMap.erase(it); return 0; } @@ -209,7 +205,7 @@ namespace vfs if (it == this->FileMap.end()) ReturnLogError(-EBADF, "Invalid fd %d", fd); - return it->second.Node->Read(buf, count, it->second.Offset); + return fs->Read(it->second.node, buf, count, it->second.Offset); } ssize_t FileDescriptorTable::usr_pread(int fd, void *buf, size_t count, off_t offset) @@ -218,7 +214,7 @@ namespace vfs if (it == this->FileMap.end()) ReturnLogError(-EBADF, "Invalid fd %d", fd); - return it->second.Node->Read(buf, count, offset); + return fs->Read(it->second.node, buf, count, offset); } ssize_t FileDescriptorTable::usr_write(int fd, const void *buf, size_t count) @@ -227,7 +223,7 @@ namespace vfs if (it == this->FileMap.end()) ReturnLogError(-EBADF, "Invalid fd %d", fd); - return it->second.Node->Write(buf, count, it->second.Offset); + return fs->Write(it->second.node, buf, count, it->second.Offset); } ssize_t FileDescriptorTable::usr_pwrite(int fd, const void *buf, size_t count, off_t offset) @@ -236,7 +232,7 @@ namespace vfs if (it == this->FileMap.end()) ReturnLogError(-EBADF, "Invalid fd %d", fd); - return it->second.Node->Write(buf, count, offset); + return fs->Write(it->second.node, buf, count, offset); } int FileDescriptorTable::usr_close(int fd) @@ -260,21 +256,19 @@ namespace vfs { case SEEK_SET: { - newOffset = it->second.Node->Seek(offset); + newOffset = fs->Seek(it->second.node, offset); break; } case SEEK_CUR: { - newOffset = it->second.Node->Seek(newOffset + offset); + newOffset = fs->Seek(it->second.node, newOffset + offset); break; } case SEEK_END: { - struct kstat stat - { - }; - it->second.Node->Stat(&stat); - newOffset = it->second.Node->Seek(stat.Size + offset); + struct kstat stat{}; + fs->Stat(it->second.node, &stat); + newOffset = fs->Seek(it->second.node, stat.Size + offset); break; } default: @@ -284,48 +278,48 @@ namespace vfs return newOffset; } - int FileDescriptorTable::usr_stat(const char *pathname, - struct kstat *statbuf) + int FileDescriptorTable::usr_stat(const char *pathname, kstat *statbuf) { - FileNode *node = fs->GetByPath(pathname, nullptr); - if (node == nullptr) - ReturnLogError(-ENOENT, "Failed to find %s", pathname); + Node root = thisProcess->Info.RootNode; + eNode ret = fs->Lookup(root, pathname); + if (ret == false) + ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what()); + Node node = ret; if (node->IsSymbolicLink()) { std::unique_ptr buffer(new char[1024]); - ssize_t ret = node->ReadLink(buffer.get(), 1024); - if (ret < 0) - return ret; + ssize_t len = fs->ReadLink(node, buffer.get(), 1024); + if (len < 0) + return len; - FileNode *target = fs->GetByPath(buffer.get(), nullptr); - if (target == nullptr) - return -ENOENT; - - return target->Stat(statbuf); + ret = fs->Lookup(root, buffer.get()); + if (ret == false) + return -ret.Error; + return fs->Stat(ret.Value, statbuf); } - return node->Stat(statbuf); + return fs->Stat(node, statbuf); } - int FileDescriptorTable::usr_fstat(int fd, struct kstat *statbuf) + int FileDescriptorTable::usr_fstat(int fd, kstat *statbuf) { auto it = this->FileMap.find(fd); if (it == this->FileMap.end()) ReturnLogError(-EBADF, "Invalid fd %d", fd); vfs::FileDescriptorTable::Fildes &fildes = it->second; - - return fildes.Node->Stat(statbuf); + return fs->Stat(fildes.node, statbuf); } - int FileDescriptorTable::usr_lstat(const char *pathname, - struct kstat *statbuf) + int FileDescriptorTable::usr_lstat(const char *pathname, kstat *statbuf) { - FileNode *node = fs->GetByPath(pathname, nullptr); - if (node == nullptr) - ReturnLogError(-ENOENT, "Failed to find %s", pathname); - return node->Stat(statbuf); + Node root = thisProcess->Info.RootNode; + eNode ret = fs->Lookup(root, pathname); + if (ret == false) + ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what()); + + return fs->Stat(ret.Value, statbuf); } int FileDescriptorTable::usr_dup(int oldfd) @@ -339,7 +333,7 @@ namespace vfs return -EMFILE; Fildes new_dfd{}; - new_dfd.Node = it->second.Node; + new_dfd.node = it->second.node; new_dfd.Mode = it->second.Mode; this->FileMap.insert({newfd, new_dfd}); @@ -364,7 +358,7 @@ namespace vfs this->usr_close(newfd); Fildes new_dfd{}; - new_dfd.Node = it->second.Node; + new_dfd.node = it->second.node; new_dfd.Mode = it->second.Mode; this->FileMap.insert({newfd, new_dfd}); @@ -378,7 +372,7 @@ namespace vfs if (it == this->FileMap.end()) ReturnLogError(-EBADF, "Invalid fd %d", fd); - return it->second.Node->Ioctl(request, argp); + return fs->Ioctl(it->second.node, request, argp); } FileDescriptorTable::FileDescriptorTable(void *_Owner) @@ -386,11 +380,12 @@ namespace vfs { debug("+ %#lx", this); - mode_t Mode = S_IXOTH | S_IROTH | - S_IXGRP | S_IRGRP | - S_IXUSR | S_IRUSR | + /* d r-x r-x r-x */ + mode_t Mode = S_IROTH | S_IXOTH | + S_IRGRP | S_IXGRP | + S_IRUSR | S_IXUSR | S_IFDIR; - - this->fdDir = fs->Create(((Tasking::PCB *)_Owner)->ProcDirectory, "fd", Mode); + Tasking::PCB *pcb = (Tasking::PCB *)_Owner; + this->fdDir = fs->Create(pcb->ProcDirectory, "fd", Mode); } } diff --git a/Kernel/storage/fs/ramfs.cpp b/Kernel/fs/ramfs.cpp similarity index 88% rename from Kernel/storage/fs/ramfs.cpp rename to Kernel/fs/ramfs.cpp index 56a9ff8d..f0f34e24 100644 --- a/Kernel/storage/fs/ramfs.cpp +++ b/Kernel/fs/ramfs.cpp @@ -15,12 +15,12 @@ along with Fennix Kernel. If not, see . */ -#include +#include #include #include #include -#include "../../kernel.h" +#include "../kernel.h" namespace vfs { @@ -81,7 +81,6 @@ namespace vfs inode.Index = NextInode; inode.Offset = 0; inode.PrivateData = this; - inode.Flags = I_FLAG_CACHE_KEEP; const char *basename; size_t length; @@ -329,54 +328,54 @@ namespace vfs } } -O2 int __ramfs_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result) +int __ramfs_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result) { return ((vfs::RAMFS *)Parent->PrivateData)->Lookup(Parent, Name, Result); } -O2 int __ramfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result) +int __ramfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result) { return ((vfs::RAMFS *)Parent->PrivateData)->Create(Parent, Name, Mode, Result); } -O2 ssize_t __ramfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) +ssize_t __ramfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) { return ((vfs::RAMFS *)Node->PrivateData)->Read(Node, Buffer, Size, Offset); } -O2 ssize_t __ramfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) +ssize_t __ramfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) { return ((vfs::RAMFS *)Node->PrivateData)->Write(Node, Buffer, Size, Offset); } -O2 ssize_t __ramfs_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) +ssize_t __ramfs_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { return ((vfs::RAMFS *)Node->PrivateData)->ReadDir(Node, Buffer, Size, Offset, Entries); } -O2 int __ramfs_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result) +int __ramfs_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result) { return ((vfs::RAMFS *)Parent->PrivateData)->SymLink(Parent, Name, Target, Result); } -O2 ssize_t __ramfs_ReadLink(Inode *Node, char *Buffer, size_t Size) +ssize_t __ramfs_ReadLink(Inode *Node, char *Buffer, size_t Size) { return ((vfs::RAMFS *)Node->PrivateData)->ReadLink(Node, Buffer, Size); } -O2 int __ramfs_Stat(struct Inode *Node, kstat *Stat) +int __ramfs_Stat(struct Inode *Node, kstat *Stat) { return ((vfs::RAMFS *)Node->PrivateData)->Stat(Node, Stat); } -O2 int __ramfs_DestroyInode(FileSystemInfo *Info, Inode *Node) +int __ramfs_DestroyInode(FileSystemInfo *Info, Inode *Node) { vfs::RAMFS::RAMFSInode *inode = (vfs::RAMFS::RAMFSInode *)Node; delete inode; return 0; } -O2 int __ramfs_Destroy(FileSystemInfo *fsi) +int __ramfs_Destroy(FileSystemInfo *fsi) { assert(fsi->PrivateData); delete (vfs::RAMFS *)fsi->PrivateData; @@ -384,16 +383,13 @@ O2 int __ramfs_Destroy(FileSystemInfo *fsi) return 0; } -bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index) +bool MountAndRootRAMFS(Node Parent, const char *Name, size_t Index) { vfs::RAMFS *ramfs = new vfs::RAMFS; - ramfs->DeviceID = fs->EarlyReserveDevice(); ramfs->RootName.assign(Name); FileSystemInfo *fsi = new FileSystemInfo; fsi->Name = "ramfs"; - fsi->RootName = Name; - fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; fsi->SuperOps.DeleteInode = __ramfs_DestroyInode; fsi->SuperOps.Destroy = __ramfs_Destroy; fsi->Ops.Lookup = __ramfs_Lookup; @@ -405,13 +401,12 @@ bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index) fsi->Ops.ReadLink = __ramfs_ReadLink; fsi->Ops.Stat = __ramfs_Stat; fsi->PrivateData = ramfs; + ramfs->DeviceID = fs->RegisterFileSystem(fsi); Inode *root = nullptr; ramfs->Create(nullptr, Name, S_IFDIR | 0755, &root); - fs->LateRegisterFileSystem(ramfs->DeviceID, fsi, root); - fs->AddRootAt(root, Index); - - fs->Mount(Parent, root, Name); + fs->Mount(Parent, root, Name, fsi); + fs->AddRoot(Index, fs->Convert(root)); return true; } diff --git a/Kernel/storage/fs/ustar.cpp b/Kernel/fs/ustar.cpp similarity index 96% rename from Kernel/storage/fs/ustar.cpp rename to Kernel/fs/ustar.cpp index 1c929dc8..762d7267 100644 --- a/Kernel/storage/fs/ustar.cpp +++ b/Kernel/fs/ustar.cpp @@ -15,12 +15,12 @@ along with Fennix Kernel. If not, see . */ -#include +#include #include #include #include -#include "../../kernel.h" +#include "../kernel.h" #define TMAGIC "ustar" #define TMAGLEN 6 @@ -32,7 +32,7 @@ namespace vfs int USTAR::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) { auto Parent = (USTARInode *)_Parent; - + debug("looking up for %s", Name); const char *basename; size_t length; cwk_path_get_basename(Name, &basename, &length); @@ -91,7 +91,6 @@ namespace vfs inode.Index = NextInode; inode.Offset = 0; inode.PrivateData = this; - inode.Flags = I_FLAG_CACHE_KEEP; const char *basename; size_t length; @@ -217,6 +216,7 @@ namespace vfs { /* FIXME: FIX ALIGNMENT FOR DIRENT! */ auto Node = (USTARInode *)_Node; + debug("reading directory %s", Node->Path.c_str()); off_t realOffset = Offset; @@ -237,6 +237,7 @@ namespace vfs ent->d_type = DT_DIR; strcpy(ent->d_name, "."); totalSize += reclen; + debug("."); } if (Offset <= 1) @@ -263,6 +264,7 @@ namespace vfs ent->d_type = DT_DIR; strcpy(ent->d_name, ".."); totalSize += reclen; + debug(".."); } // off_t entriesSkipped = 0; @@ -309,10 +311,13 @@ namespace vfs if (var->Deleted) continue; - reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1); + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + var->Name.size() + 1); - if (totalSize + reclen >= Size) + if (totalSize + reclen > Size) + { + debug("not enough space for %s (%zu + %zu = %zu > %zu)", var->Name.c_str(), totalSize, reclen, totalSize + reclen, Size); break; + } ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); ent->d_ino = var->Node.Index; @@ -349,7 +354,7 @@ namespace vfs break; } strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str())); - + debug("%s", var->Name.c_str()); totalSize += reclen; entries++; } @@ -601,7 +606,6 @@ namespace vfs uNode.RawDevice = 0; uNode.Index = NextInode; SetMode(uNode, header); - uNode.Flags = I_FLAG_CACHE_KEEP; uNode.Offset = 0; uNode.PrivateData = this; @@ -847,17 +851,8 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index) return false; } - ustar->DeviceID = fs->EarlyReserveDevice(); - ustar->ReadArchive(Address, Size); - - Inode *rootfs = nullptr; - ustar->Lookup(nullptr, "/", &rootfs); - assert(rootfs != nullptr); - FileSystemInfo *fsi = new FileSystemInfo; fsi->Name = "ustar"; - 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; @@ -868,8 +863,23 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index) fsi->Ops.ReadLink = __ustar_ReadLink; fsi->Ops.Stat = __ustar_Stat; fsi->PrivateData = ustar; - fs->LateRegisterFileSystem(ustar->DeviceID, fsi, rootfs); - fs->AddRootAt(rootfs, Index); + ustar->DeviceID = fs->RegisterFileSystem(fsi); + ustar->ReadArchive(Address, Size); + + Inode *rootfs = nullptr; + ustar->Lookup(nullptr, "/", &rootfs); + assert(rootfs != nullptr); + + eNode _node = fs->Convert(rootfs); + assert(_node.Error == 0); + + Node node = _node; + node->fsi = fsi; + node->Flags.MountPoint = true; + node->Name = "/"; + node->Path = "/"; + + fs->AddRoot(Index, node); return true; } diff --git a/Kernel/fs/vfs.cpp b/Kernel/fs/vfs.cpp new file mode 100644 index 00000000..28f7db06 --- /dev/null +++ b/Kernel/fs/vfs.cpp @@ -0,0 +1,586 @@ +/* + 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 "../kernel.h" + +namespace vfs +{ + eNode Virtual::Convert(Inode *inode) + { + Node cache = std::make_shared(); + cache->inode = inode; + return {cache, 0}; + } + + eNode Virtual::Convert(Node &Parent, Inode *inode) + { + Node cache = std::make_shared(); + cache->inode = inode; + cache->fsi = Parent->fsi; + cache->Parent = Parent; + Parent->Children.push_back(cache); + return {cache, 0}; + } + + std::string Virtual::NormalizePath(Node &Parent, std::string Path, bool Join) + { + std::string result; + if (Join) + { + size_t len = Path.size() + Parent->Path.size() + 2; + result.reserve(len); + len = cwk_path_join(Parent->Path.c_str(), Path.c_str(), result.data(), result.capacity()); + result.resize(len); + return result; + } + + size_t len = Path.size() + 2; + result.reserve(len); + len = cwk_path_normalize(Path.c_str(), result.data(), result.capacity()); + result.resize(len); + return result; + } + + bool Virtual::RootExists(dev_t Index) + { + if (Roots.find(Index) == Roots.end()) + return false; + return true; + } + + eNode Virtual::GetRoot(dev_t Index) + { + auto it = Roots.find(Index); + if (it == Roots.end()) + return {nullptr, ENOENT}; + return {it->second, 0}; + } + + ssize_t Virtual::GetRoot(Node Index) + { + for (auto it = Roots.begin(); it != Roots.end(); ++it) + { + if (it->second == Index) + return it->first; + } + return -ENOENT; + } + + int Virtual::AddRoot(dev_t Index, Node Root, bool Replace) + { + assert(Root != nullptr); + + auto it = Roots.find(Index); + if (it == Roots.end()) + { + Roots[Index] = Root; + return 0; + } + + if (Replace) + { + Roots[Index] = Root; + return 0; + } + else + { + debug("Root %ld already exists", Index); + return EEXIST; + } + } + + dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi) + { + assert(fsi != nullptr); + FileSystems.insert({FileSystems.size(), fsi}); + return FileSystems.size() - 1; + } + + int Virtual::UnregisterFileSystem(dev_t Device) + { + auto it = FileSystems.find(Device); + if (it == FileSystems.end()) + return -ENOENT; + + FileSystemInfo *fsi = it->second; + + /* TODO: unmount */ + fixme("Unmounting %d", Device); + + if (fsi->SuperOps.Synchronize) + fsi->SuperOps.Synchronize(fsi, nullptr); + if (fsi->SuperOps.Destroy) + fsi->SuperOps.Destroy(fsi); + + FileSystems.erase(it); + return 0; + } + + eNode Virtual::Lookup(Node &Parent, std::string Path) + { + assert(Parent != nullptr); + + debug("looking up \"%s\" in \"%s\"", Path.c_str(), Parent->Path.c_str()); + + if (Path == ".") + return {Parent, 0}; + else if (Path == "..") + return {Parent->Parent ? Parent->Parent : Parent, 0}; + + Node base = Parent; + bool absolute = PathIsAbsolute(Path); + if (absolute == true) + { + while (base->Parent) + base = base->Parent; + } + + debug("base is \"%s\" and path is \"%s\" %d", base->Path.c_str(), Path.c_str(), absolute); + Path = this->NormalizePath(base, Path, !absolute); + debug("after normalizing, path is \"%s\" %d", Path.c_str(), absolute); + + struct cwk_segment segment; + if (!cwk_path_get_first_segment(Path.c_str(), &segment)) + { + debug("%s no segments; %d", Path.c_str(), absolute); + if (Path == "/") + return {base, 0}; + + assert(!"Path doesn't have any segments."); + } + + Node node = base; + /* We need to go to the root after NormalizePath even if Path is relative */ + if (absolute == false) + { + while (node->Parent) + { + debug("current parent \"%s\"", node->Parent->Path.c_str()); + node = node->Parent; + debug("new parent \"%s\"", node->Parent ? node->Parent->Path.c_str() : ""); + } + } + + std::string currentPath = node->Path; + if (currentPath.empty()) + currentPath = "/"; + + do + { + std::string segmentStr(segment.begin, segment.size); + debug("Current segment is \"%s\"", segmentStr.c_str()); + + eNode ret = node->CachedSearch(segmentStr); + if (ret == false) + { + debug("cache miss for \"%s\"", segmentStr.c_str()); + + if (node->fsi->Ops.Lookup == nullptr) + return {nullptr, ENOTSUP}; + + Inode *inode; + int ret = node->fsi->Ops.Lookup(node->inode, segmentStr.c_str(), &inode); + if (ret != 0) + return {nullptr, ret}; + + if (currentPath == "/") + currentPath += segmentStr; + else + currentPath += "/" + segmentStr; + + node = Convert(node, inode); + node->Name = segmentStr; + node->Path = currentPath; + } + else + { + debug("cache hit for \"%s\"", segmentStr.c_str()); + node = ret; + if (currentPath == "/") + currentPath += segmentStr; + else + currentPath += "/" + segmentStr; + } + } while (cwk_path_get_next_segment(&segment)); + + return {node, 0}; + } + + eNode Virtual::Create(Node &Parent, std::string Name, mode_t Mode, bool ErrorIfExists) + { + eNode exists = this->Lookup(Parent, Name); + if (exists) + { + if (ErrorIfExists) + return {nullptr, EEXIST}; + + /* I should handle this in a better way */ + assert((exists.Value->inode->Mode & S_IFMT) == (Mode & S_IFMT)); + debug("File \"%s\" already exists in cache", Name.c_str()); + return exists; + } + + if (!Parent) + return {nullptr, EINVAL}; + if (Parent->fsi->Ops.Create == nullptr) + return {nullptr, ENOTSUP}; + + Inode *inode; + int ret = Parent->fsi->Ops.Create(Parent->inode, Name.c_str(), Mode, &inode); + if (ret != 0) + return {nullptr, ret}; + + Node node = Convert(Parent, inode); + node->Name = Name; + std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name; + node->Path = fs->NormalizePath(Parent, unormalized); + return {node, 0}; + } + + int Virtual::Remove(Node &Parent, std::string Name) + { + if (!Parent) + return -EINVAL; + if (Parent->fsi->Ops.Remove == nullptr) + return -ENOTSUP; + int ret = Parent->fsi->Ops.Remove(Parent->inode, Name.c_str()); + if (ret == 0) + { + for (auto it = Parent->Children.begin(); it != Parent->Children.end(); ++it) + { + if (it->get()->Name != Name) + continue; + Parent->Children.erase(it); + break; + } + } + return ret; + } + + int Virtual::Remove(Node &node) + { + if (!node->Parent) + return -EINVAL; + if (node->Parent->fsi->Ops.Remove == nullptr) + return -ENOTSUP; + int ret = node->Parent->fsi->Ops.Remove(node->inode, node->Name.c_str()); + if (ret == 0) + { + Node &p = node->Parent; + for (auto it = p->Children.begin(); it != p->Children.end(); ++it) + { + if (it->get() != node.get()) + continue; + p->Children.erase(it); + break; + } + } + return ret; + } + + int Virtual::Rename(Node &node, std::string NewName) + { + if (node->fsi->Ops.Rename == nullptr) + return -ENOTSUP; + int ret = node->fsi->Ops.Rename(node->inode, node->Name.c_str(), NewName.c_str()); + if (ret == 0) + node->Name = NewName; + return ret; + } + + ssize_t Virtual::Read(Node &Target, void *Buffer, size_t Size, off_t Offset) + { + if (Target->IsDirectory() || Target->IsMountPoint()) + return -EISDIR; + + if (Target->IsSymbolicLink()) + return -EINVAL; + + /* TODO: cache buffer */ + + return Target->__Read(Buffer, Size, Offset); + } + + ssize_t Virtual::Write(Node &Target, const void *Buffer, size_t Size, off_t Offset) + { + if (Target->IsDirectory() || Target->IsMountPoint()) + return -EISDIR; + + if (Target->IsSymbolicLink()) + return -EINVAL; + + /* TODO: cache buffer */ + + return Target->__Write(Buffer, Size, Offset); + } + + int Virtual::Truncate(Node &Target, off_t Size) + { + if (Target->IsDirectory() || Target->IsMountPoint()) + return -EISDIR; + + if (!Target->IsRegularFile()) + return -EINVAL; + + /* TODO: cache buffer */ + + return Target->__Truncate(Size); + } + + __no_sanitize("alignment") ssize_t Virtual::ReadDirectory(Node &Target, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + { + if (!Target->IsDirectory() && !Target->IsMountPoint()) + return -ENOTDIR; + + ssize_t total = 0; + off_t entryIndex = 0; + std::list seen; + + uint8_t *bufPtr = reinterpret_cast(Buffer); + + if (Target->fsi && Target->fsi->Ops.ReadDir) + { + const size_t tempBufSize = 4096; + std::unique_ptr tempBuf(new uint8_t[tempBufSize]); + + off_t fsOffset = Offset; + ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)tempBuf.get(), tempBufSize, fsOffset, Entries); + if (read > 0) + { + ssize_t pos = 0; + while (pos < read) + { + kdirent *ent = (kdirent *)(tempBuf.get() + pos); + if (ent->d_reclen == 0) + break; + + size_t reclen = ent->d_reclen; + if (total + reclen > Size) + break; + + memcpy(bufPtr, ent, reclen); + seen.push_back(ent->d_name); + bufPtr += reclen; + total += reclen; + pos += reclen; + entryIndex++; + } + } + } + + for (const auto &child : Target->Children) + { + if (std::find(seen.begin(), seen.end(), child->Name) != seen.end()) + continue; + + if (entryIndex < Offset) + { + entryIndex++; + continue; + } + + uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + child->Name.size() + 1); + if (total + reclen > (ssize_t)Size) + break; + + kdirent *ent = (kdirent *)bufPtr; + ent->d_ino = child->inode ? child->inode->Index : 0; + ent->d_off = entryIndex++; + ent->d_reclen = reclen; + ent->d_type = child->inode ? IFTODT(child->inode->Mode) : DT_UNKNOWN; + strcpy(ent->d_name, child->Name.c_str()); + + bufPtr += reclen; + total += reclen; + seen.push_back(child->Name); + } + + return total; + } + + __no_sanitize("alignment") std::list Virtual::ReadDirectory(Node &Target) + { + if (!Target->IsDirectory() && !Target->IsMountPoint()) + return {}; + std::list ret; + std::list seen; + + if (Target->fsi && Target->fsi->Ops.ReadDir) + { + const size_t bufSize = 4096; + std::unique_ptr buf(new uint8_t[bufSize]); + off_t offset = 0; + while (true) + { + ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)buf.get(), bufSize, offset, LONG_MAX); + if (read <= 0) + break; + ssize_t pos = 0; + while (pos < read) + { + kdirent *ent = (kdirent *)(buf.get() + pos); + if (ent->d_reclen == 0) + break; + debug("%s", ent->d_name); + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) + { + pos += ent->d_reclen; + continue; + } + + seen.push_back(ent->d_name); + + auto it = std::find_if(Target->Children.begin(), Target->Children.end(), + [&](const Node &n) + { return n->Name == ent->d_name; }); + + if (it != Target->Children.end()) + ret.push_back(*it); + else + { + eNode result = Lookup(Target, ent->d_name); + if (result.Error == 0 && result.Value) + { + Target->Children.push_back(result.Value); + result.Value->Parent = Target; + ret.push_back(result.Value); + } + } + pos += ent->d_reclen; + } + offset += read; + } + } + + for (const auto &child : Target->Children) + { + if (std::find(seen.begin(), seen.end(), child->Name) != seen.end()) + continue; + if (child->Name == "." || child->Name == "..") + continue; + ret.push_back(child); + seen.push_back(child->Name.c_str()); + } + + return ret; + } + + eNode Virtual::CreateLink(Node &Parent, std::string Name, std::string Target) + { + mode_t mode = S_IRWXU | + S_IRWXG | + S_IRWXO | + S_IFLNK; + + eNode enode = this->Create(Parent, Name, mode); + if (!enode) + return enode; + Node node = enode; + node->Link = Target; + return {node, 0}; + } + + int Virtual::Stat(Node &Target, struct kstat *Stat) + { + /* TODO: cache */ + + return Target->__Stat(Stat); + } + + off_t Virtual::Seek(Node &Target, off_t Offset) + { + /* TODO: cache */ + + return Target->__Seek(Offset); + } + + int Virtual::Open(Node &Target, int Flags, mode_t Mode) + { + /* TODO: cache */ + + return Target->__Open(Flags, Mode); + } + + int Virtual::Close(Node &Target) + { + /* TODO: cache */ + + return Target->__Close(); + } + + eNode Virtual::Mount(Node &Parent, Inode *inode, std::string Name, FileSystemInfo *fsi) + { + assert(Parent); + assert(inode); + + Node ret = this->Convert(inode); + ret->fsi = fsi; + ret->Name = Name; + + std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name; + ret->Path = fs->NormalizePath(Parent, unormalized); + // ret->Link = + ret->Parent = Parent; + Parent->Children.push_back(ret); + return {ret, 0}; + } + + int Virtual::Umount(Node &node) + { + if (!node->Flags.MountPoint) + { + debug("node %s is not a mountpoint", node->Path.c_str()); + return -EINVAL; + } + + fixme("untested code"); + std::shared_ptr &ptr = node; + ptr.reset(); + return 0; + } + + int Virtual::Umount(Node &Parent, std::string Name) + { + eNode node = Parent->CachedSearch(Name); + if (!node) + { + debug("mountpoint %s not found: %s", Name.c_str(), node.what()); + return -node.Error; + } + + return this->Umount(node.Value); + } + + void Virtual::Initialize() + { + debug("Initializing virtual file system..."); + Node root = this->GetRoot(0); + + /* d rwx rwx rwx */ + mode_t mode = S_IRWXU | + S_IRWXG | + S_IRWXO | + S_IFDIR; + Node var = this->Create(root, "var", mode, false); + Node log = this->Create(var, "log", mode, false); + } + + Virtual::Virtual() {} + Virtual::~Virtual() {} +} diff --git a/Kernel/include/driver.hpp b/Kernel/include/driver.hpp index a7e3a0c6..1202dc54 100644 --- a/Kernel/include/driver.hpp +++ b/Kernel/include/driver.hpp @@ -22,7 +22,8 @@ #include #include -#include +#include +#include #include #include #include @@ -120,17 +121,15 @@ namespace Driver * 1 - input/... devices */ dev_t DriverIDCounter = 2; - FileNode *devNode = nullptr; - FileNode *devInputNode = nullptr; + Node devNode = nullptr; + Node devInputNode = nullptr; + Node devBlockNode = nullptr; - bool IsDriverTrusted(FileNode *File); - int LoadDriverFile(DriverObject &Drv, FileNode *File); + bool IsDriverTrusted(Node File); + int LoadDriverFile(DriverObject &Drv, Node File); void ReloadDriver(dev_t driverID); - 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 *); + void InitializeDeviceDirectory(); public: RingBuffer GlobalKeyboardInputReports; @@ -138,11 +137,16 @@ namespace Driver struct DeviceInode { - struct Inode Node; - FileNode *Parent; + struct Inode inode; + Node Parent; Inode *ParentInode; std::string Name; std::vector Children; + + size_t Size; + time_t AccessTime, ModifyTime, ChangeTime; + uint32_t BlockSize; + uint32_t Blocks; }; std::unordered_map & @@ -185,6 +189,9 @@ namespace Driver int ReportInputEvent(dev_t DriverID, InputReport *Report); int UnregisterDevice(dev_t DriverID, dev_t Device); + dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device); + int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID); + void *AllocateMemory(dev_t DriverID, size_t Pages); void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages); @@ -193,8 +200,6 @@ namespace Driver private: ~Manager(); }; - - void ManagerDaemonWrapper(); } void *GetSymbolByName(const char *Name, int Version); @@ -215,9 +220,12 @@ namespace v0 int UnregisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler); int UnregisterAllInterruptHandlers(dev_t DriverID, void *Handler); - dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root); + dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info); int UnregisterFileSystem(dev_t DriverID, dev_t Device); + dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device); + int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID); + pid_t CreateKernelProcess(dev_t DriverID, const char *Name); pid_t CreateKernelThread(dev_t DriverID, pid_t pId, const char *Name, void *EntryPoint, void *Argument); pid_t GetCurrentProcess(dev_t DriverID); diff --git a/Kernel/include/exec.hpp b/Kernel/include/exec.hpp index be31797b..79fc3330 100644 --- a/Kernel/include/exec.hpp +++ b/Kernel/include/exec.hpp @@ -20,7 +20,7 @@ #include -#include +#include #include #include #include @@ -50,15 +50,15 @@ namespace Execute void *ELFProgramHeaders; void GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma, - FileNode *fd, Elf_Ehdr ELFHeader, + Node &fd, Elf_Ehdr ELFHeader, uintptr_t EntryPoint, uintptr_t BaseAddress); - void LoadSegments(FileNode *fd, Tasking::PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress); + void LoadSegments(Node &fd, Tasking::PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress); - void LoadExec(FileNode *fd, Tasking::PCB *TargetProcess); - void LoadDyn(FileNode *fd, Tasking::PCB *TargetProcess); - bool LoadInterpreter(FileNode *fd, Tasking::PCB *TargetProcess); + void LoadExec(Node &fd, Tasking::PCB *TargetProcess); + void LoadDyn(Node &fd, Tasking::PCB *TargetProcess); + bool LoadInterpreter(Node &fd, Tasking::PCB *TargetProcess); public: decltype(IsElfValid) &IsValid = IsElfValid; @@ -74,7 +74,7 @@ namespace Execute ~ELFObject(); }; - BinaryType GetBinaryType(FileNode *Path); + BinaryType GetBinaryType(Node &Path); BinaryType GetBinaryType(std::string Path); int Spawn(const char *Path, const char **argv, const char **envp, @@ -88,12 +88,12 @@ namespace Execute char *GetELFStringTable(Elf_Ehdr *Header); char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset); Elf_Sym *ELFLookupSymbol(Elf_Ehdr *Header, std::string Name); - Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name); + Elf_Sym ELFLookupSymbol(Node &fd, std::string Name); uintptr_t ELFGetSymbolValue(Elf_Ehdr *Header, uintptr_t Table, uintptr_t Index); - std::vector ELFGetSymbolType(FileNode *fd, SegmentTypes Tag); - std::vector ELFGetSections(FileNode *fd, std::string SectionName); - std::vector ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag); + std::vector ELFGetSymbolType(Node &fd, SegmentTypes Tag); + std::vector ELFGetSections(Node &fd, std::string SectionName); + std::vector ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag); } #endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__ diff --git a/Kernel/include/filesystem.hpp b/Kernel/include/filesystem.hpp deleted file mode 100644 index bda0be7d..00000000 --- a/Kernel/include/filesystem.hpp +++ /dev/null @@ -1,260 +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 . -*/ - -#ifndef __FENNIX_KERNEL_FILESYSTEM_H__ -#define __FENNIX_KERNEL_FILESYSTEM_H__ - -#include - -#include -#include -#include -#include -#include -#include -#include - -static_assert(DTTOIF(DT_FIFO) == S_IFIFO); -static_assert(IFTODT(S_IFCHR) == DT_CHR); - -/** - * This macro is used to check if a filesystem operation is available. - * - * TL;DR - * - * @code - * if FileSystemInfo.Ops.op == nullptr - * return -err - * else - * return FileSystemInfo.Ops.op(this->Node, ...); - * @endcode - * - * @param op The operation to check. - * @param err The error to return if the operation is not available. - * @param ... The arguments to pass to the operation. - * - * @return The result of the operation. - */ -#define __check_op(op, err, ...) \ - if (fsi->Ops.op == nullptr) \ - return -err; \ - else \ - return fsi->Ops.op(this->Node, ##__VA_ARGS__) - -#define FSROOT(num) "\x06root-" #num "\x06" - -class FileNode -{ -public: - std::string Name, Path; - FileNode *Parent; - std::vector Children; - Inode *Node; - FileSystemInfo *fsi; - - std::string GetName(); - std::string GetPath(); - - bool IsDirectory() { return S_ISDIR(Node->Mode); } - bool IsCharacterDevice() { return S_ISCHR(Node->Mode); } - bool IsBlockDevice() { return S_ISBLK(Node->Mode); } - bool IsRegularFile() { return S_ISREG(Node->Mode); } - bool IsFIFO() { return S_ISFIFO(Node->Mode); } - bool IsSymbolicLink() { return S_ISLNK(Node->Mode); } - bool IsSocket() { return S_ISSOCK(Node->Mode); } - - int Lookup(const char *Name, Inode **Node) { __check_op(Lookup, ENOTSUP, Name, Node); } - int Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, EROFS, Name, Mode, Node); } - int Remove(const char *Name) { __check_op(Remove, EROFS, Name); } - int Rename(const char *OldName, const char *NewName) { __check_op(Rename, EROFS, OldName, NewName); } - ssize_t Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, ENOTSUP, (void *)Buffer, Size, Offset); } - ssize_t Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, EROFS, (const void *)Buffer, Size, Offset); } - int Truncate(off_t Size) { __check_op(Truncate, EROFS, Size); } - int Open(int Flags, mode_t Mode) { __check_op(Open, ENOTSUP, Flags, Mode); } - int Close() { __check_op(Close, ENOTSUP); } - int Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, ENOTSUP, Request, Argp); } - ssize_t ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, ENOTSUP, Buffer, Size, Offset, Entries); } - int MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, EROFS, Name, Mode, Result); } - int RmDir(const char *Name) { __check_op(RmDir, EROFS, Name); } - int SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, EROFS, Name, Target, Result); } - ssize_t ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, ENOTSUP, (char *)Buffer, Size); } - off_t Seek(off_t Offset) { __check_op(Seek, ENOTSUP, Offset); } - int Stat(struct kstat *Stat) { __check_op(Stat, ENOTSUP, Stat); } - - ~FileNode() = delete; -}; - -#undef __check_op - -namespace vfs -{ - struct vfsInode - { - Inode Node; - std::string Name; - std::string FriendlyName; - std::vector Children; - }; - - class Virtual - { - private: - NewLock(VirtualLock); - - struct FSMountInfo - { - FileSystemInfo *fsi; - Inode *Root; - }; - - struct CacheNode - { - FileNode *fn; - std::atomic_int References; - }; - - std::unordered_map DeviceMap; - std::atomic_bool RegisterLock = false; - - FileNode *CacheSearchReturnLast(FileNode *Parent, const char **Path); - FileNode *CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName); - FileNode *CacheLookup(FileNode *Parent, const char *Path); - FileNode *CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode); - - int RemoveCacheNode(FileNode *Node); - - public: - vfsInode *FileSystemRoots = nullptr; - - /** - * Default reserved roots: - * - * 0 - Native - * 1 - Linux - * 2 - Windows - */ - std::unordered_map FileRoots; - - bool PathIsRelative(const char *Path); - bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); } - - /** - * Reserve a device number for a filesystem - * - * @note After this function is called, the filesystem must - * call LateRegisterFileSystem to release the lock - */ - dev_t EarlyReserveDevice(); - - /** - * Register a filesystem after the device number has been reserved - */ - int LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root); - - dev_t RegisterFileSystem(FileSystemInfo *fsi, Inode *Root); - int UnregisterFileSystem(dev_t Device); - - void AddRoot(Inode *Root); - void AddRootAt(Inode *Root, size_t Index); - bool SetRootAt(Inode *Root, size_t Index); - void RemoveRoot(Inode *Root); - FileNode *GetRoot(size_t Index); - bool RootExists(size_t Index); - - 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); - - int Remove(FileNode *Node); - - void Initialize(); - Virtual(); - ~Virtual(); - }; - - class FileDescriptorTable - { - public: - struct Fildes - { - enum FildesType - { - FD_INODE, - FD_PIPE, - FD_SOCKET, - } Type; - mode_t Mode = 0; - int Flags = 0; - FileNode *Node = nullptr; - int References = 0; - off_t Offset = 0; - - int operator==(const Fildes &other) - { - return Type == other.Type && - Mode == other.Mode && - Flags == other.Flags && - Node == other.Node && - References == other.References && - Offset == other.Offset; - } - }; - - private: - FileNode *fdDir = nullptr; - void *Owner; - - int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags); - int RemoveFileDescriptor(int FileDescriptor); - int GetFreeFileDescriptor(); - - public: - std::unordered_map FileMap; - - int GetFlags(int FileDescriptor); - int SetFlags(int FileDescriptor, int Flags); - void Fork(FileDescriptorTable *Parent); - - int usr_open(const char *pathname, int flags, mode_t mode); - int usr_creat(const char *pathname, mode_t mode); - ssize_t usr_read(int fd, void *buf, size_t count); - ssize_t usr_write(int fd, const void *buf, size_t count); - ssize_t usr_pread(int fd, void *buf, size_t count, off_t offset); - ssize_t usr_pwrite(int fd, const void *buf, size_t count, off_t offset); - int usr_close(int fd); - off_t usr_lseek(int fd, off_t offset, int whence); - int usr_stat(const char *pathname, struct kstat *statbuf); - int usr_fstat(int fd, struct kstat *statbuf); - int usr_lstat(const char *pathname, struct kstat *statbuf); - int usr_dup(int oldfd); - int usr_dup2(int oldfd, int newfd); - int usr_ioctl(int fd, unsigned long request, void *argp); - - FileDescriptorTable(void *Owner); - ~FileDescriptorTable() = default; - }; -} - -#endif // !__FENNIX_KERNEL_FILESYSTEM_H__ diff --git a/Kernel/include/filesystem/initrd.hpp b/Kernel/include/filesystem/initrd.hpp deleted file mode 100644 index 833eac78..00000000 --- a/Kernel/include/filesystem/initrd.hpp +++ /dev/null @@ -1,48 +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 . -*/ - -#ifndef __FENNIX_KERNEL_FILESYSTEM_INITRD_H__ -#define __FENNIX_KERNEL_FILESYSTEM_INITRD_H__ - -#include - -#include - -namespace vfs -{ - class Initrd - { - public: - struct InitrdHeader - { - uint32_t nfiles; - }; - - struct InitrdFileHeader - { - uint8_t magic; - char name[64]; - uint32_t offset; - uint32_t length; - }; - - Initrd(uintptr_t Address); - ~Initrd(); - }; -} - -#endif // !__FENNIX_KERNEL_FILESYSTEM_INITRD_H__ diff --git a/Kernel/include/fs/fdt.hpp b/Kernel/include/fs/fdt.hpp new file mode 100644 index 00000000..13553554 --- /dev/null +++ b/Kernel/include/fs/fdt.hpp @@ -0,0 +1,86 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include + +namespace vfs +{ + class FileDescriptorTable + { + public: + struct Fildes + { + enum FildesType + { + FD_INODE, + FD_PIPE, + FD_SOCKET, + } Type; + mode_t Mode = 0; + int Flags = 0; + Node node = nullptr; + int References = 0; + off_t Offset = 0; + + int operator==(const Fildes &other) + { + return Type == other.Type && + Mode == other.Mode && + Flags == other.Flags && + node.get() == other.node.get() && + References == other.References && + Offset == other.Offset; + } + }; + + private: + Node fdDir = nullptr; + void *Owner; + + int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags); + int RemoveFileDescriptor(int FileDescriptor); + int GetFreeFileDescriptor(); + + public: + std::unordered_map FileMap; + + int GetFlags(int FileDescriptor); + int SetFlags(int FileDescriptor, int Flags); + void Fork(FileDescriptorTable *Parent); + + int usr_open(const char *pathname, int flags, mode_t mode); + int usr_creat(const char *pathname, mode_t mode); + ssize_t usr_read(int fd, void *buf, size_t count); + ssize_t usr_write(int fd, const void *buf, size_t count); + ssize_t usr_pread(int fd, void *buf, size_t count, off_t offset); + ssize_t usr_pwrite(int fd, const void *buf, size_t count, off_t offset); + int usr_close(int fd); + off_t usr_lseek(int fd, off_t offset, int whence); + int usr_stat(const char *pathname, kstat *statbuf); + int usr_fstat(int fd, kstat *statbuf); + int usr_lstat(const char *pathname, kstat *statbuf); + int usr_dup(int oldfd); + int usr_dup2(int oldfd, int newfd); + int usr_ioctl(int fd, unsigned long request, void *argp); + + FileDescriptorTable(void *Owner); + ~FileDescriptorTable() = default; + }; +} diff --git a/Kernel/include/filesystem/ioctl.hpp b/Kernel/include/fs/ioctl.hpp similarity index 100% rename from Kernel/include/filesystem/ioctl.hpp rename to Kernel/include/fs/ioctl.hpp diff --git a/Kernel/include/fs/node.hpp b/Kernel/include/fs/node.hpp new file mode 100644 index 00000000..3dc97aae --- /dev/null +++ b/Kernel/include/fs/node.hpp @@ -0,0 +1,207 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include +#include +#include + +/** + * This macro is used to check if a filesystem operation is available. + * + * TL;DR + * + * @code + * if FileSystemInfo.Ops.op == nullptr + * return -err + * else + * return FileSystemInfo.Ops.op(this->Node, ...); + * @endcode + * + * @param op The operation to check. + * @param err The error to return if the operation is not available. + * @param ... The arguments to pass to the operation. + * + * @return The result of the operation. + */ +#define __check_op(op, err, ...) \ + if (unlikely(fsi->Ops.op == nullptr)) \ + return -err; \ + else \ + return fsi->Ops.op(this->inode, ##__VA_ARGS__) + +namespace vfs +{ + class NodeObject + { + public: + Inode *inode; + FileSystemInfo *fsi; + union + { + struct + { + uint8_t MountPoint : 1; + uint8_t __reserved : 7; + }; + uint8_t raw; + } Flags; + + int __Lookup(const char *Name, Inode **Node) { __check_op(Lookup, ENOTSUP, Name, Node); } + int __Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, ENOTSUP, Name, Mode, Node); } + int __Remove(const char *Name) { __check_op(Remove, ENOTSUP, Name); } + int __Rename(const char *OldName, const char *NewName) { __check_op(Rename, ENOTSUP, OldName, NewName); } + ssize_t __Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, ENOTSUP, (void *)Buffer, Size, Offset); } + ssize_t __Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, ENOTSUP, (const void *)Buffer, Size, Offset); } + int __Truncate(off_t Size) { __check_op(Truncate, ENOTSUP, Size); } + int __Open(int Flags, mode_t Mode) { __check_op(Open, ENOTSUP, Flags, Mode); } + int __Close() { __check_op(Close, ENOTSUP); } + int __Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, ENOTSUP, Request, Argp); } + ssize_t __ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, ENOTSUP, Buffer, Size, Offset, Entries); } + int __MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, ENOTSUP, Name, Mode, Result); } + int __RmDir(const char *Name) { __check_op(RmDir, ENOTSUP, Name); } + int __SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, ENOTSUP, Name, Target, Result); } + ssize_t __ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, ENOTSUP, (char *)Buffer, Size); } + off_t __Seek(off_t Offset) { __check_op(Seek, ENOTSUP, Offset); } + int __Stat(struct kstat *Stat) { __check_op(Stat, ENOTSUP, Stat); } + + ~NodeObject() + { + debug("%#lx destructor called", this); + } + }; +} + +class NodeCache; + +/** + * @brief Node is a type that represents a filesystem node. + * It is a shared pointer to a NodeCache object. + * + * If the refcount of the NodeCache object goes to zero, the data is synced to disk. + */ +typedef std::shared_ptr Node; + +/** + * @brief NodeResult is a type that represents the result of a filesystem operation. + * It contains a Node object and an error code. + */ +typedef struct NodeResult +{ + /* Value must be the first member of the struct to allow for implicit conversion */ + Node Value; + int Error; + + operator bool() const { return Error == 0 && Value.get() != nullptr; } + operator Node() const { return Value; } + const char *what() const { return strerror(Error); } +} eNode; + +class NodeCache : public vfs::NodeObject +{ +public: + std::string Name, Path, Link; + + /** + * @brief Parent of this node + * + * Maximum depth is 1, otherwise undefined behavior. + */ + Node Parent; + + /** + * @brief Childrens of this node + * + * On access, children are loaded, but not children of children! + * Accessing children of children is undefined behavior. + */ + std::vector Children; + + std::string GetName() { return Name; } + std::string GetPath() { return Path; } + std::string GetLink() { return Link; } + + bool IsDirectory() { return S_ISDIR(inode->Mode); } + bool IsCharacterDevice() { return S_ISCHR(inode->Mode); } + bool IsBlockDevice() { return S_ISBLK(inode->Mode); } + bool IsRegularFile() { return S_ISREG(inode->Mode); } + bool IsFIFO() { return S_ISFIFO(inode->Mode); } + bool IsSymbolicLink() { return S_ISLNK(inode->Mode); } + bool IsSocket() { return S_ISSOCK(inode->Mode); } + bool IsMountPoint() { return Flags.MountPoint; } + + /** + * @brief Search through the cached children of this node + * + * Searches through the cached children of this node. + * + * @param Name The name to search for + * @return 0 and a Node on success, ENOENT on failure + */ + eNode CachedSearch(std::string Name) + { + for (auto it = Children.begin(); it != Children.end(); ++it) + { + if ((*it).get() == nullptr) + { + Children.erase(it); + continue; + } + + debug("comparing \"%s\" with \"%s\"", (*it)->Name.c_str(), Name.c_str()); + if ((*it)->Name == Name) + { + debug("\"%s\" found", Name.c_str()); + return {*it, 0}; + } + } + + return {nullptr, ENOENT}; + } + + /** + * @brief Get the allocation size of this object + * + * @return The allocated size + */ + size_t GetAllocationSize() + { + size_t size = sizeof(NodeCache); + size += Name.capacity(); + size += Path.capacity(); + size += Link.capacity(); + size += Children.capacity(); + return size; + } + + ~NodeCache() + { + debug("%#lx\"%s\" destructor called", this, Name.c_str()); + + if (this->Parent) + this->Parent->Children.erase(std::remove(this->Parent->Children.begin(), this->Parent->Children.end(), Node(this)), this->Parent->Children.end()); + + if (fsi->SuperOps.Synchronize) + fsi->SuperOps.Synchronize(this->fsi, this->inode); + + // FIXME: recursive deletion of nodes children + } +}; + +#undef __check_op diff --git a/Kernel/include/filesystem/ramfs.hpp b/Kernel/include/fs/ramfs.hpp similarity index 97% rename from Kernel/include/filesystem/ramfs.hpp rename to Kernel/include/fs/ramfs.hpp index bd39df3a..fc846dd6 100644 --- a/Kernel/include/filesystem/ramfs.hpp +++ b/Kernel/include/fs/ramfs.hpp @@ -17,7 +17,7 @@ #pragma once -#include +#include #include namespace vfs @@ -147,4 +147,4 @@ namespace vfs }; } -bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index); +bool MountAndRootRAMFS(Node Parent, const char *Name, size_t Index); diff --git a/Kernel/include/filesystem/ustar.hpp b/Kernel/include/fs/ustar.hpp similarity index 99% rename from Kernel/include/filesystem/ustar.hpp rename to Kernel/include/fs/ustar.hpp index b714b5d4..83286255 100644 --- a/Kernel/include/filesystem/ustar.hpp +++ b/Kernel/include/fs/ustar.hpp @@ -18,7 +18,7 @@ #ifndef __FENNIX_KERNEL_FILESYSTEM_USTAR_H__ #define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__ -#include +#include namespace vfs { diff --git a/Kernel/include/fs/vfs.hpp b/Kernel/include/fs/vfs.hpp new file mode 100644 index 00000000..0cabf605 --- /dev/null +++ b/Kernel/include/fs/vfs.hpp @@ -0,0 +1,179 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +/* sanity checks */ +static_assert(DTTOIF(DT_FIFO) == S_IFIFO); +static_assert(IFTODT(S_IFCHR) == DT_CHR); + +namespace vfs +{ + class Virtual + { + private: + std::unordered_map Roots; + std::unordered_map FileSystems; + + public: +#pragma region Utilities + + inline bool PathIsRelative(const char *Path) { return cwk_path_is_relative(Path); } + inline bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); } + inline bool PathIsRelative(std::string &Path) { return cwk_path_is_relative(Path.c_str()); } + inline bool PathIsAbsolute(std::string &Path) { return !PathIsRelative(Path.c_str()); } + + eNode Convert(Node node) { return {node, 0}; } + + /** + * @brief Converts an Inode to a Node + * + * Result of this function will be empty. + * You are responsible to populate the Node. + * + * @param inode Inode to convert + * @return eNode{Node, errno} + */ + eNode Convert(Inode *inode); + + /** + * @brief Converts an Inode to a Node + * + * Result of this function will be populated using the Parent Node. + * This function will automatically assign the FSI, parents and children. + * + * @note Name and Path won't be set. + * + * @param Parent Parent Node + * @param inode Inode to convert + * @return eNode{Node, errno} + */ + eNode Convert(Node &Parent, Inode *inode); + + /** + * @brief Normalizes a path + * + * If the path is relative, it will be normalized using the Parent Node. + * Example if Join is true: + * Parent = /home/user/Desktop + * Path = ../Documents + * Result = /home/user/Documents + * + * If Join is false: + * Path = /var/foo/bar/../../ + * Result = /var + * + * @param Parent Parent Node + * @param Path Path to normalize + * @param Join If true, the path will be joined with the Parent Node + * @return Normalized Path + */ + std::string NormalizePath(Node &Parent, std::string Path, bool Join = false); + +#pragma endregion Utilities + +#pragma region Roots + + bool RootExists(dev_t Index); + eNode GetRoot(dev_t Index); + ssize_t GetRoot(Node Index); + int AddRoot(dev_t Index, Node Root, bool Replace = false); + int AddRoot(dev_t Index, eNode Root, bool Replace = false) { return AddRoot(Index, Root.Value, Replace); } + +#pragma endregion Roots + +#pragma region Registrations + + dev_t RegisterFileSystem(FileSystemInfo *fsi); + int UnregisterFileSystem(dev_t Device); + +#pragma endregion Registrations + +#pragma region Node Operations + + eNode Lookup(Node &Parent, std::string Path); + + eNode Create(Node &Parent, std::string Name, mode_t Mode, bool ErrorIfExists = true); + + int Remove(Node &Parent, std::string Name); + int Remove(Node &node); + + int Rename(Node &node, std::string NewName); + + ssize_t Read(Node &Target, void *Buffer, size_t Size, off_t Offset); + ssize_t Write(Node &Target, const void *Buffer, size_t Size, off_t Offset); + + int Truncate(Node &Target, off_t Size); + + /** + * @brief Read directory entries + * + * @note This function includes "." and ".." + * + * @param Target + * @param Buffer + * @param Size + * @param Offset + * @param Entries + * @return + */ + ssize_t ReadDirectory(Node &Target, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries); + + /** + * @brief Read directory entries + * + * @note This function does NOT include "." and ".." + * + * @param Target + * @return + */ + std::list ReadDirectory(Node &Target); + + eNode CreateLink(Node &Parent, std::string Name, std::string Target); + eNode CreateLink(Node &Parent, std::string Name, Node &Target) { return this->CreateLink(Parent, Name, Target->Path); } + + int Stat(Node &Target, kstat *Stat); + int ReadLink(Node &Target, char *Buffer, size_t Size) { return Target->__ReadLink(Buffer, Size); } + off_t Seek(Node &Target, off_t Offset); + + int Open(Node &Target, int Flags, mode_t Mode); + int Close(Node &Target); + int Ioctl(Node &Target, unsigned long Request, void *Argp) { return Target->__Ioctl(Request, Argp); } + +#pragma endregion Node Operations + +#pragma region Mounting + + eNode Mount(Node &Parent, Inode *inode, std::string Name, FileSystemInfo *fsi); + + int Umount(Node &node); + int Umount(Node &Parent, std::string Name); + +#pragma endregion Mounting + + void Initialize(); + Virtual(); + ~Virtual(); + }; +} diff --git a/Kernel/include/interface/block.h b/Kernel/include/interface/block.h new file mode 100644 index 00000000..45c6ce29 --- /dev/null +++ b/Kernel/include/interface/block.h @@ -0,0 +1,110 @@ +/* + 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_BLOCK_H__ +#define __FENNIX_API_BLOCK_H__ + +#include + +#if __has_include() +#include +#else +#include +#endif + +struct BlockDevice +{ + /** + * @brief Base name of the device. + * + * This name is used to identify the device in the system. It should be unique + * across all block devices. The kernel may append a number to this name to + * create a unique device name (e.g., "ahci0", "ahci1"). + */ + const char *Name; + + /** + * @brief Total size of the device in bytes. + * + * This value represents the total addressable storage capacity of the device. + * It is used for bounds checking and partitioning. + */ + size_t Size; + + /** + * @brief Size of a single block in bytes. + * + * All read and write operations are performed in multiples of this block size. + * Typical values are 512 or 4096 bytes. + */ + uint32_t BlockSize; + + /** + * @brief Number of blocks in the device. + * + * This value is calculated as Size / BlockSize. It represents the total number + * of addressable blocks on the device. + */ + size_t BlockCount; + + /** + * @brief Pointer to the block device operations structure. + * + * This structure contains function pointers for various operations that can + * be performed on the block device, such as read, write, and ioctl. + * + * Yea, inode operations are used for block devices too. + */ + const InodeOperations *Ops; + + /** + * @brief Opaque pointer to driver-specific or hardware-specific data. + * + * This field allows the driver to associate private context or state with the + * device, such as controller registers or internal buffers. + */ + void *PrivateData; +}; + +#ifndef __kernel__ +/** + * @brief Registers a block device with the kernel block subsystem. + * + * This function should be called by block device drivers after initializing + * a device. The kernel will take ownership of the device structure and assign + * it a unique device ID. The device will then be accessible for filesystem + * mounting and I/O operations. + * + * @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device. + * @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure. + */ +dev_t RegisterBlockDevice(struct BlockDevice *Device); + +/** + * @brief Unregisters a block device from the kernel block subsystem. + * + * This function should be called by drivers when a device is being removed + * or is no longer available. The kernel will release any resources associated + * with the device and invalidate its device ID. + * + * @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice(). + * @return 0 on success, or an error code. + */ +int UnregisterBlockDevice(dev_t DeviceID); +#endif // __kernel__ + +#endif // __FENNIX_API_BLOCK_H__ diff --git a/Kernel/include/interface/fs.h b/Kernel/include/interface/fs.h index 3abe9a75..c55969d5 100644 --- a/Kernel/include/interface/fs.h +++ b/Kernel/include/interface/fs.h @@ -322,10 +322,6 @@ struct InodeOperations 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 { @@ -337,8 +333,8 @@ struct SuperBlockOperations * * Write all pending changes to the disk. * - * @param Info Inode to synchronize. If NULL, synchronize all inodes. - * @param Node Inode to synchronize. + * @param Info Inode to synchronize. + * @param Node Inode to synchronize. If NULL, synchronize all inodes. * * @return Zero on success, otherwise an error code. */ @@ -354,13 +350,50 @@ struct SuperBlockOperations * @return Zero on success, otherwise an error code. */ int (*Destroy)(struct FileSystemInfo *Info); + + /** + * Probe the filesystem. + * + * Check if the filesystem is supported by the driver. + * + * @param Device Device to probe. + * + * @return Zero on success, otherwise an error code. + */ + int (*Probe)(void *Device); + + /** + * Mount the filesystem. + * + * Mount the filesystem on the given device. + * + * @param FS Filesystem to mount. + * @param Root Pointer to the root inode. + * @param Device Device to mount. + * + * @return Zero on success, otherwise an error code. + */ + int (*Mount)(struct FileSystemInfo *FS, struct Inode **Root, void *Device); + + /** + * Unmount the filesystem. + * + * Unmount the filesystem from the given device. + * + * @param FS Filesystem to unmount. + * + * @return Zero on success, otherwise an error code. + */ + int (*Unmount)(struct FileSystemInfo *FS); } __attribute__((packed)); struct FileSystemInfo { const char *Name; - const char *RootName; + int Flags; + int Capabilities; + struct SuperBlockOperations SuperOps; struct InodeOperations Ops; @@ -368,6 +401,9 @@ struct FileSystemInfo } __attribute__((packed)); #ifndef __kernel__ +dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root); +int UnregisterMountPoint(dev_t Device); + dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root); int UnregisterFileSystem(dev_t Device); #endif // !__kernel__ diff --git a/Kernel/include/memory.hpp b/Kernel/include/memory.hpp index 61d4a972..a26dcc3f 100644 --- a/Kernel/include/memory.hpp +++ b/Kernel/include/memory.hpp @@ -19,7 +19,7 @@ #define __FENNIX_KERNEL_INTERNAL_MEMORY_H__ #ifdef __cplusplus -#include +#include #include #include #include diff --git a/Kernel/include/memory/vma.hpp b/Kernel/include/memory/vma.hpp index 1dfe8358..2abe448c 100644 --- a/Kernel/include/memory/vma.hpp +++ b/Kernel/include/memory/vma.hpp @@ -19,7 +19,7 @@ #define __FENNIX_KERNEL_MEMORY_VMA_H__ #include -#include +#include #include #include #include diff --git a/Kernel/include/task.hpp b/Kernel/include/task.hpp index 105b0a1e..02dda6b1 100644 --- a/Kernel/include/task.hpp +++ b/Kernel/include/task.hpp @@ -20,7 +20,7 @@ #include -#include +#include #include #include #include @@ -219,7 +219,7 @@ namespace Tasking TaskArchitecture Architecture = TaskArchitecture::UnknownArchitecture; TaskCompatibility Compatibility = TaskCompatibility::UnknownPlatform; cwk_path_style PathStyle = CWK_STYLE_UNIX; - FileNode *RootNode = nullptr; + Node RootNode = nullptr; }; struct ThreadLocalStorage @@ -445,7 +445,7 @@ namespace Tasking PID ID = -1; const char *Name = nullptr; PCB *Parent = nullptr; - FileNode *ProcDirectory = nullptr; + Node ProcDirectory = nullptr; /* Statuses */ std::atomic_int ExitCode; @@ -489,14 +489,14 @@ namespace Tasking } Linux{}; /* Filesystem */ - FileNode *CWD; - FileNode *Executable; + Node CWD; + Node Executable; FileDescriptorTable *FileDescriptors; /* stdio */ - FileNode *stdin; - FileNode *stdout; - FileNode *stderr; + Node stdin; + Node stdout; + Node stderr; /*TTY::TeletypeDriver*/ void *tty; /* Memory */ @@ -521,7 +521,7 @@ namespace Tasking void SetState(TaskState state); void SetExitCode(int code); void Rename(const char *name); - void SetWorkingDirectory(FileNode *node); + void SetWorkingDirectory(Node node); void SetExe(const char *path); size_t GetSize(); TCB *GetThread(TID ID); diff --git a/Kernel/include/types.h b/Kernel/include/types.h index 817b21d4..232727fd 100644 --- a/Kernel/include/types.h +++ b/Kernel/include/types.h @@ -458,6 +458,10 @@ typedef uint48_t uint_fast48_t; #define hot __attribute__((hot)) #define cold __attribute__((cold)) +#define OPTIONAL +#define IN +#define OUT + #define NoSecurityAnalysis __no_stack_protector __no_sanitize_address __no_sanitize_undefined __no_sanitize_thread #define nsa NoSecurityAnalysis diff --git a/Kernel/kernel.cpp b/Kernel/kernel.cpp index 41fbe7ed..b74689da 100644 --- a/Kernel/kernel.cpp +++ b/Kernel/kernel.cpp @@ -17,7 +17,7 @@ #include "kernel.h" -#include +#include #include #include #include diff --git a/Kernel/kernel.h b/Kernel/kernel.h index 3b4718c1..2e8d54e7 100644 --- a/Kernel/kernel.h +++ b/Kernel/kernel.h @@ -22,7 +22,7 @@ #include #ifdef __cplusplus -#include +#include #include #include #include diff --git a/Kernel/kernel_thread.cpp b/Kernel/kernel_thread.cpp index 755a440d..668d6854 100644 --- a/Kernel/kernel_thread.cpp +++ b/Kernel/kernel_thread.cpp @@ -20,7 +20,7 @@ #include "tests/t.h" #endif -#include +#include #include #include #include @@ -70,11 +70,11 @@ int SpawnLinuxInit() "/startup/init"}; const char *foundPath = nullptr; - FileNode *root = fs->GetRoot(1); + Node root = fs->GetRoot(1); for (const std::string &path : fallbackPaths) { const char *str = path.c_str(); - if (!fs->PathExists(str, root)) + if (fs->Lookup(root, str) == false) continue; foundPath = str; break; @@ -123,8 +123,6 @@ void KernelMainThread() KPrint("Initializing Driver Manager"); DriverManager = new Driver::Manager; - TaskManager->CreateThread(thisProcess, Tasking::IP(Driver::ManagerDaemonWrapper)) - ->Rename("Device Service"); KPrint("Loading Drivers"); DriverManager->PreloadDrivers(); diff --git a/Kernel/kernel_vfs.cpp b/Kernel/kernel_vfs.cpp index 64f90c1c..8ae960fc 100644 --- a/Kernel/kernel_vfs.cpp +++ b/Kernel/kernel_vfs.cpp @@ -17,7 +17,7 @@ #include "kernel.h" -#include +#include #include vfs::Virtual *fs = nullptr; diff --git a/Kernel/kshell/commands/cat.cpp b/Kernel/kshell/commands/cat.cpp index 9f18556c..253f42d8 100644 --- a/Kernel/kshell/commands/cat.cpp +++ b/Kernel/kshell/commands/cat.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" @@ -28,7 +28,7 @@ void cmd_cat(const char *args) if (args[0] == '\0') return; - FileNode *node = fs->GetByPath(args, nullptr); + Node node = fs->Lookup(thisProcess->CWD, args); if (node == nullptr) { @@ -48,11 +48,11 @@ void cmd_cat(const char *args) return; } - kstat stat = {}; - node->Stat(&stat); + kstat stat; + fs->Stat(node, &stat); uint8_t *buffer = new uint8_t[stat.Size + 1]; - ssize_t rBytes = node->Read(buffer, stat.Size, 0); + ssize_t rBytes = fs->Read(node, buffer, stat.Size, 0); if (rBytes > 0) printf("%s\n", buffer); else diff --git a/Kernel/kshell/commands/cd.cpp b/Kernel/kshell/commands/cd.cpp index 64f2a508..2ad61013 100644 --- a/Kernel/kshell/commands/cd.cpp +++ b/Kernel/kshell/commands/cd.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" @@ -28,8 +28,7 @@ void cmd_cd(const char *args) if (args[0] == '\0') return; - FileNode *node = fs->GetByPath(args, nullptr); - + Node node = fs->Lookup(thisProcess->CWD, args); if (node == nullptr) { printf("cd: %s: No such file or directory\n", args); @@ -43,4 +42,5 @@ void cmd_cd(const char *args) } thisProcess->CWD = node; + debug("changed cwd to %s", node->Path.c_str()); } diff --git a/Kernel/kshell/commands/dump.cpp b/Kernel/kshell/commands/dump.cpp index 3218e9a1..df7691d8 100644 --- a/Kernel/kshell/commands/dump.cpp +++ b/Kernel/kshell/commands/dump.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" @@ -38,9 +38,41 @@ void cmd_dump(const char *args) *strLen = '\0'; strLen++; - void *Address = (void *)strtoul(strAddr, nullptr, 16); + void *Address; unsigned long Length = strtoul(strLen, nullptr, 10); + Node root = fs->GetRoot(0); + Node fileNode = fs->Lookup(root, strAddr); + if (fileNode && !fileNode->IsDirectory() && !fileNode->IsFIFO() && !fileNode->IsSocket()) + { + kstat stat; + int status = fs->Stat(fileNode, &stat); + if (status != 0) + { + printf("cannot get stat: %s\n", strerror(status)); + return; + } + + size_t size = stat.Size > (off_t)Length ? Length : stat.Size; + Address = new char[size]; /* FIXME: memory leak */ + size_t read = fs->Read(fileNode, Address, size, 0); + if (read < Length) + { + debug("clamp %lu to %lu", Length, read); + Length = read; + } + } + else + { + if (fileNode) + { + printf("file %s cannot be dumped\n", strAddr); + return; + } + Address = (void *)strtoul(strAddr, nullptr, 16); + debug("address %s", strAddr); + } + { unsigned char *AddressChar = (unsigned char *)Address; unsigned char Buffer[17]; @@ -74,4 +106,4 @@ void cmd_dump(const char *args) } putchar('\n'); } -} \ No newline at end of file +} diff --git a/Kernel/kshell/commands/exit.cpp b/Kernel/kshell/commands/exit.cpp index 20dcb9d9..07339e32 100644 --- a/Kernel/kshell/commands/exit.cpp +++ b/Kernel/kshell/commands/exit.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/kill.cpp b/Kernel/kshell/commands/kill.cpp index 76879a76..b124bb0c 100644 --- a/Kernel/kshell/commands/kill.cpp +++ b/Kernel/kshell/commands/kill.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/killall.cpp b/Kernel/kshell/commands/killall.cpp index 80f30b99..28bac761 100644 --- a/Kernel/kshell/commands/killall.cpp +++ b/Kernel/kshell/commands/killall.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/ls.cpp b/Kernel/kshell/commands/ls.cpp index e7c7c98c..52ca6d46 100644 --- a/Kernel/kshell/commands/ls.cpp +++ b/Kernel/kshell/commands/ls.cpp @@ -17,98 +17,60 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" using namespace vfs; -const char *ColorNodeType(FileNode *node) +const char *ColorNodeType(Node node) { if (node->IsRegularFile()) - return "\x1b[32m"; + return "\x1b[0m"; else if (node->IsDirectory()) - return "\x1b[34m"; + return "\x1b[1;34m"; else if (node->IsBlockDevice()) - return "\x1b[33m"; + return "\x1b[1;33m"; else if (node->IsCharacterDevice()) - return "\x1b[33m"; + return "\x1b[1;33m"; else if (node->IsFIFO()) - return "\x1b[33m"; + return "\x1b[0;33m"; else if (node->IsSymbolicLink()) - return "\x1b[35m"; + return "\x1b[1;36m"; else return "\x1b[0m"; } -__no_sanitize("alignment") size_t MaxNameLength(FileNode *nodes) +__no_sanitize("alignment") void PrintLS(Node node) { - size_t maxLength = 0; - - 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); + size_t maxNameLength = 0; 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; + std::list children = fs->ReadDirectory(node); - 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); + for (auto &&i : children) + std::max(maxNameLength, i->Name.length()); + + for (auto &&i : children) + { + if (count % 5 == 0 && !first) + printf("\n"); + + printf(" %s%-*s ", ColorNodeType(i), (int)maxNameLength, i->Name.c_str()); + + count++; + first = false; } printf("\x1b[0m\n"); - delete[] dirBuffer; } void cmd_ls(const char *args) { if (args[0] == '\0') { - FileNode *rootNode = thisProcess->CWD; + Node rootNode = thisProcess->CWD; if (rootNode == nullptr) rootNode = fs->GetRoot(0); @@ -117,7 +79,7 @@ void cmd_ls(const char *args) return; } - FileNode *thisNode = fs->GetByPath(args, nullptr); + Node thisNode = fs->Lookup(thisProcess->CWD, args); if (thisNode == nullptr) { diff --git a/Kernel/kshell/commands/lsacpi.cpp b/Kernel/kshell/commands/lsacpi.cpp index 586bad7b..94fb622f 100644 --- a/Kernel/kshell/commands/lsacpi.cpp +++ b/Kernel/kshell/commands/lsacpi.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/lspci.cpp b/Kernel/kshell/commands/lspci.cpp index 246ed1d7..457d10a7 100644 --- a/Kernel/kshell/commands/lspci.cpp +++ b/Kernel/kshell/commands/lspci.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/mem.cpp b/Kernel/kshell/commands/mem.cpp index 1b2e51a1..2a096437 100644 --- a/Kernel/kshell/commands/mem.cpp +++ b/Kernel/kshell/commands/mem.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/panic.cpp b/Kernel/kshell/commands/panic.cpp index 19dc8fce..8fc63273 100644 --- a/Kernel/kshell/commands/panic.cpp +++ b/Kernel/kshell/commands/panic.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/ps.cpp b/Kernel/kshell/commands/ps.cpp index d160b8a2..6fc28fbc 100644 --- a/Kernel/kshell/commands/ps.cpp +++ b/Kernel/kshell/commands/ps.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/reboot.cpp b/Kernel/kshell/commands/reboot.cpp index a9da5456..47d002a2 100644 --- a/Kernel/kshell/commands/reboot.cpp +++ b/Kernel/kshell/commands/reboot.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/shutdown.cpp b/Kernel/kshell/commands/shutdown.cpp index 0d3acea6..790c8083 100644 --- a/Kernel/kshell/commands/shutdown.cpp +++ b/Kernel/kshell/commands/shutdown.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/top.cpp b/Kernel/kshell/commands/top.cpp index 2d97bb5d..de2d4e50 100644 --- a/Kernel/kshell/commands/top.cpp +++ b/Kernel/kshell/commands/top.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/tree.cpp b/Kernel/kshell/commands/tree.cpp index d12cab90..3bb771ea 100644 --- a/Kernel/kshell/commands/tree.cpp +++ b/Kernel/kshell/commands/tree.cpp @@ -17,70 +17,38 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" -void tree_loop(FileNode *rootNode, int depth = 0) +// Enhancing the tree_loop function to display a fancier tree structure + +__no_sanitize("alignment") void tree_loop(Node rootNode, int depth = 0, std::string prefix = "") { - // for (auto Child : 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); - // } + std::list children = fs->ReadDirectory(rootNode); + size_t count = children.size(); + size_t index = 0; - 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; + for (auto &&child : children) + { + if (child->Name == "." || child->Name == "..") + continue; - 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; + bool isLast = (++index == count); - if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) - continue; + printf("%s%s- %s\n", prefix.c_str(), isLast ? "\\" : "|-", child->Name.c_str()); - 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; + if (child->IsDirectory()) + { + std::string newPrefix = prefix + (isLast ? " " : "| "); + tree_loop(child, depth + 1, newPrefix); + } + } } void cmd_tree(const char *args) { - FileNode *rootNode = thisProcess->CWD; + Node rootNode = thisProcess->CWD; if (args[0] == '\0') { if (rootNode == nullptr) @@ -88,7 +56,7 @@ void cmd_tree(const char *args) } else { - rootNode = fs->GetByPath(args, nullptr); + rootNode = fs->Lookup(thisProcess->CWD, args); if (rootNode == nullptr) { printf("ls: %s: No such file or directory\n", args); diff --git a/Kernel/kshell/commands/uname.cpp b/Kernel/kshell/commands/uname.cpp index 0a525e60..713273d4 100644 --- a/Kernel/kshell/commands/uname.cpp +++ b/Kernel/kshell/commands/uname.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/uptime.cpp b/Kernel/kshell/commands/uptime.cpp index bea39681..718c2131 100644 --- a/Kernel/kshell/commands/uptime.cpp +++ b/Kernel/kshell/commands/uptime.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" diff --git a/Kernel/kshell/commands/whoami.cpp b/Kernel/kshell/commands/whoami.cpp index ba2a2ce2..6c77857f 100644 --- a/Kernel/kshell/commands/whoami.cpp +++ b/Kernel/kshell/commands/whoami.cpp @@ -17,7 +17,7 @@ #include "../cmds.hpp" -#include +#include #include "../../kernel.h" diff --git a/Kernel/kshell/shell.cpp b/Kernel/kshell/shell.cpp index e70b89a2..283646ec 100644 --- a/Kernel/kshell/shell.cpp +++ b/Kernel/kshell/shell.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -88,6 +88,7 @@ void KShellThread() KPrint("Starting kernel shell..."); thisThread->SetPriority(Tasking::TaskPriority::Normal); + thisProcess->CWD = fs->GetRoot(0); std::string strBuf = ""; std::vector history; @@ -97,7 +98,8 @@ void KShellThread() bool tabDblPress = false; const char *keyDevPath = "/dev/input/keyboard"; - FileNode *kfd = fs->GetByPath(keyDevPath, fs->GetRoot(0)); + Node root = fs->GetRoot(0); + Node kfd = fs->Lookup(root, keyDevPath); if (kfd == nullptr) { KPrint("Failed to open keyboard device!"); @@ -125,21 +127,20 @@ void KShellThread() debug("clearing strBuf(\"%s\")", strBuf.c_str()); strBuf.clear(); - FileNode *cwd = thisProcess->CWD; + Node cwd = thisProcess->CWD; if (!cwd) cwd = fs->GetRoot(0); - std::string cwdStr = fs->GetByNode(cwd); - debug("cwd: %*s", (int)cwdStr.size(), cwdStr.c_str()); + debug("cwd: %s", cwd->Path.c_str()); printf("\x1b[1;34m%s@%s:%s$ \x1b[0m", "kernel", "fennix", - cwdStr.c_str()); + cwd->Path.c_str()); KeyboardReport scBuf{}; ssize_t nBytes; while (true) { - nBytes = kfd->Read(&scBuf, sizeof(KeyboardReport), 0); + nBytes = fs->Read(kfd, &scBuf, sizeof(KeyboardReport), 0); if (nBytes == 0) { debug("Empty read from keyboard device!"); @@ -561,14 +562,14 @@ void KShellThread() if (fs->PathIsRelative(cmd_only.c_str())) { path += cmd_only; - if (!fs->PathExists(path.c_str(), nullptr)) + if (!fs->Lookup(root, path.c_str())) path = "/usr/bin/" + cmd_only; } else path = cmd_only; debug("path: %s", path.c_str()); - if (fs->PathExists(path.c_str(), nullptr)) + if (fs->Lookup(root, path.c_str())) { const char *envp[5] = { "PATH=/bin:/usr/bin", diff --git a/Kernel/library/kexcept/cxxabi.cpp b/Kernel/library/kexcept/cxxabi.cpp index 40d544d5..70838bd0 100644 --- a/Kernel/library/kexcept/cxxabi.cpp +++ b/Kernel/library/kexcept/cxxabi.cpp @@ -158,11 +158,9 @@ void terminate_header_stub() CPU::Stop(); /* FIXME: Panic */ } -void exception_cleanup_stub(_Unwind_Reason_Code Code, - _Unwind_Exception *Exception) +void exception_cleanup_stub(_Unwind_Reason_Code Code, _Unwind_Exception *Exception) { - fixme("exception_cleanup( %d %p ) called.", - Code, Exception); + fixme("exception_cleanup( %d %p ) called.", Code, Exception); } extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw() @@ -175,12 +173,10 @@ extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw() return Exception + 1; } -extern "C" __noreturn void __cxa_throw(void *thrown_object, - std::type_info *tinfo, - void (*dest)(void *)) +extern "C" __noreturn void __cxa_throw(void *thrown_object, void *tinfo, void (*dest)(void *)) { trace("Throwing exception of type \"%s\". ( object: %p, destructor: %p )", - tinfo->name(), thrown_object, dest); + ((std::type_info *)tinfo)->name(), thrown_object, dest); __cxa_eh_globals *Globals = __cxa_get_globals(); Globals->uncaughtExceptions++; @@ -218,10 +214,9 @@ extern "C" void __cxa_throw_bad_array_new_length() fixme("__cxa_throw_bad_array_new_length() called."); } -extern "C" void __cxa_free_exception(void *thrown_exception) +extern "C" void __cxa_free_exception(void *thrown_exception) throw() { - fixme("__cxa_free_exception( %p ) called.", - thrown_exception); + fixme("__cxa_free_exception( %p ) called.", thrown_exception); } __extension__ typedef int __guard __attribute__((mode(__DI__))); diff --git a/Kernel/storage/cache.cpp b/Kernel/storage/cache.cpp deleted file mode 100644 index bc801785..00000000 --- a/Kernel/storage/cache.cpp +++ /dev/null @@ -1,227 +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 - -#include -#include -#include -#include - -#include "../kernel.h" - -namespace vfs -{ - FileNode *Virtual::CacheSearchReturnLast(FileNode *Parent, const char **Path) - { - assert(Parent != nullptr); - - struct cwk_segment segment; - if (!cwk_path_get_first_segment(*Path, &segment)) - { - if (strcmp(*Path, Parent->fsi->RootName) == 0) - return Parent; - - 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 *tmpPath = *Path; - if (strncmp(tmpPath, "\x06root-", 6) == 0) /* FIXME: deduce the index */ - { - tmpPath += 6; - while (*tmpPath != '\0' && *tmpPath != '\x06') - tmpPath++; - if (*tmpPath == '\x06') - tmpPath++; - } - else - tmpPath = *Path; - - FileNode *__Parent = Parent; - if (this->PathIsAbsolute(tmpPath)) - { - while (__Parent->Parent) - __Parent = __Parent->Parent; - } - - cwk_path_get_first_segment(tmpPath, &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; - - 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)) - { - if (strcmp(NameOrPath, Root->fsi->RootName) == 0) - return Root; - 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) - { - 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, "\x06root-", 6) == 0) /* FIXME: deduce the index */ - { - path += 6; - while (*path != '\0' && *path != '\x06') - path++; - if (*path == '\x06') - path++; - } - else - path = NameOrPath; - - FileNode *__Parent = Root; - if (this->PathIsAbsolute(path)) - { - /* Get the root if Root is not the root 【・_・?】 */ - 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; - 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; - } - - FileNode *Virtual::CacheLookup(FileNode *Parent, const char *Path) - { - debug("Cache lookup for \"%s\"", Path); - if (Parent == nullptr) - Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0); - - FileNode *ret = CacheRecursiveSearch(Parent, Path, false); - if (ret) - return ret; - - debug("Path \"%s\" not found", Path); - return nullptr; - } - - FileNode *Virtual::CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode) - { - FileNode *fn = new FileNode; - fn->Name = Name; - if (Parent) - { - fn->Path = Parent->Path + "/" + Name; - Parent->Children.push_back(fn); - } - else - fn->Path = Name; - fn->Parent = Parent; - fn->Node = Node; - fn->fsi = DeviceMap[Node->Device].fsi; - if (fn->fsi == nullptr) - warn("Failed to find filesystem for device %d", Node->Device); - - debug("Created cache node %s", fn->Path.c_str()); - return fn; - } - - int Virtual::RemoveCacheNode(FileNode *Node) - { - if (Node == nullptr) - return -EINVAL; - - if (Node->Parent) - { - Node->Parent->Children.erase(std::find(Node->Parent->Children.begin(), Node->Parent->Children.end(), Node)); - // delete Node; - fixme("Node deletion is disabled for now (for debugging purposes)"); - } - - return 0; - } -} diff --git a/Kernel/storage/filesystem.cpp b/Kernel/storage/filesystem.cpp deleted file mode 100644 index c055feb2..00000000 --- a/Kernel/storage/filesystem.cpp +++ /dev/null @@ -1,390 +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 - -#include -#include -#include -#include - -#include "../kernel.h" - -namespace vfs -{ - bool Virtual::PathIsRelative(const char *Path) - { - return cwk_path_is_relative(Path); - } - - void Virtual::AddRoot(Inode *Root) - { - SmartLock(VirtualLock); - FileSystemRoots->Children.push_back(Root); - } - - void Virtual::AddRootAt(Inode *Root, size_t Index) - { - SmartLock(VirtualLock); - if (Index >= FileSystemRoots->Children.size()) - FileSystemRoots->Children.resize(Index + 1); - - if (FileSystemRoots->Children[Index] == nullptr) - FileSystemRoots->Children[Index] = Root; - else - { - debug("Root %ld already exists", Index); - } - } - - bool Virtual::SetRootAt(Inode *Root, size_t Index) - { - SmartLock(VirtualLock); - assert(Index < FileSystemRoots->Children.size()); - - if (FileSystemRoots->Children[Index] != nullptr) - { - debug("Root %ld already exists", Index); - return false; - } - FileSystemRoots->Children[Index] = Root; - return true; - } - - void Virtual::RemoveRoot(Inode *Root) - { - SmartLock(VirtualLock); - for (size_t i = 0; i < FileSystemRoots->Children.size(); i++) - { - if (FileSystemRoots->Children[i] != Root) - continue; - FileSystemRoots->Children[i] = nullptr; - break; - } - debug("removed root %p", Root); - } - - FileNode *Virtual::GetRoot(size_t Index) - { - assert(Index < FileSystemRoots->Children.size()); - - auto it = FileRoots.find(Index); - if (it != FileRoots.end()) - return it->second; - - Inode *rootNode = FileSystemRoots->Children[Index]; - assert(rootNode != nullptr); - char rootName[128]{}; - snprintf(rootName, sizeof(rootName), "\x06root-%ld\x06", Index); - FileNode *ret = this->CreateCacheNode(nullptr, rootNode, rootName, 0); - FileRoots.insert({Index, ret}); - return ret; - } - - bool Virtual::RootExists(size_t Index) - { - if (Index >= FileSystemRoots->Children.size()) - return false; - return FileSystemRoots->Children[Index] != nullptr; - } - - FileNode *Virtual::Create(FileNode *Parent, const char *Name, mode_t Mode) - { - FileNode *existingNode = this->GetByPath(Name, Parent); - if (existingNode != nullptr) - ReturnLogError(existingNode, "File %s already exists", Name); - - if (Parent == nullptr) - { - assert(thisProcess != nullptr); - Parent = thisProcess->Info.RootNode; - } - - auto it = DeviceMap.find(Parent->Node->Device); - if (it == DeviceMap.end()) - ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device); - - Inode *Node = NULL; - if (it->second.fsi->Ops.Create == NULL) - ReturnLogError(nullptr, "Create not supported for %d", it->first); - - int ret = it->second.fsi->Ops.Create(Parent->Node, Name, Mode, &Node); - if (ret < 0) - ReturnLogError(nullptr, "Create for %d failed with %d", it->first, ret); - - return this->CreateCacheNode(Parent, Node, Name, Mode); - } - - FileNode *Virtual::ForceCreate(FileNode *Parent, const char *Name, mode_t Mode) - { - fixme("ForceCreate: %s", Name); - 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) - { - if (lastSlash == path) - lastSlash++; - *lastSlash = '\0'; - } - - FileNode *parentNode = this->GetByPath(path, Parent); - if (parentNode == nullptr && Parent != nullptr) - parentNode = Parent; - free(path); - lastSlash = strrchr(Path, '/'); - if (lastSlash) - lastSlash++; - else - lastSlash = (char *)Path; - 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) - { - debug("GetByPath: %s", Path); - if (Parent == nullptr) - { - if (fs->PathIsRelative(Path)) - Parent = thisProcess ? thisProcess->CWD : thisProcess->Info.RootNode; - else - Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0); - } - - 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, "\x06root-", 6) == 0) /* FIXME: deduce the index */ - { - Path += 7; - while (*Path != '\0' && *Path != '\x06') - Path++; - if (*Path == '\x06') - 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; - bool readSymlinks = true; /* FIXME: implement */ - do - { - auto it = DeviceMap.find(__Parent->Node->Device); - if (unlikely(it == DeviceMap.end())) - ReturnLogError(nullptr, "Device %d not found", __Parent->Node->Device); - debug("found fs %s", it->second.fsi->Name); - - if (it->second.fsi->Ops.Lookup == NULL) - ReturnLogError(nullptr, "Lookup not supported for %d", it->first); - - if (readSymlinks && __Parent->IsSymbolicLink()) - { - if (it->second.fsi->Ops.ReadLink == NULL) - ReturnLogError(nullptr, "Readlink not supported for %d", it->first); - - char buffer[256]; - int ret = it->second.fsi->Ops.ReadLink(__Parent->Node, buffer, sizeof(buffer)); - if (ret < 0) - ReturnLogError(nullptr, "Readlink for \"%s\"(%d) failed with %d", __Parent->Path.c_str(), it->first, ret); - - FileNode *target = this->GetByPath(buffer, __Parent->Parent ? __Parent->Parent : __Parent); - if (target == nullptr) - ReturnLogError(nullptr, "Failed to find target for \"%s\"", __Parent->Path.c_str()); - __Parent = target; - } - - 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 \"%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)); - - FileNode *ret = __Parent; - 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 .. */ - while (it->second.fsi->Ops.ReadDir(Node, dirent, dirAllocLen, offset++, 1) > 0) - { - Inode *ChildNode = NULL; - int luRet = it->second.fsi->Ops.Lookup(Node, dirent->d_name, &ChildNode); - if (luRet < 0) - { - debug("Lookup for %d failed with %d", it->first, luRet); - break; - } - - this->CreateCacheNode(ret, ChildNode, dirent->d_name, 0); - } - free(dirent); - return ret; - } - - std::string Virtual::GetByNode(FileNode *Node) - { - assert(Node != nullptr); - 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); - if (it == DeviceMap.end()) - ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device); - - Inode *Node = NULL; - - if (it->second.fsi->Ops.SymLink == NULL) - ReturnLogError(nullptr, "SymLink not supported for %d", it->first); - - int ret = it->second.fsi->Ops.SymLink(Parent->Node, Path, Target, &Node); - if (ret < 0) - ReturnLogError(nullptr, "SymLink for %d failed with %d", it->first, ret); - return this->CreateCacheNode(Parent, Node, Path, 0); - } - - FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, FileNode *Target) - { - return this->CreateLink(Path, Parent, Target->Path.c_str()); - } - - bool Virtual::PathExists(const char *Path, FileNode *Parent) - { - FileNode *fn = this->CacheLookup(Parent, Path); - if (fn) - return true; - - FileNode *Node = this->GetByPath(Path, Parent); - if (Node) - return true; - return false; - } - - int Virtual::Remove(FileNode *Node) - { - auto it = DeviceMap.find(Node->Node->Device); - if (it == DeviceMap.end()) - ReturnLogError(-ENODEV, "Device %d not found", Node->Node->Device); - - if (it->second.fsi->Ops.Remove == NULL) - ReturnLogError(-ENOTSUP, "Remove not supported for %d", it->first); - - int ret = it->second.fsi->Ops.Remove(Node->Parent->Node, Node->Name.c_str()); - if (ret < 0) - ReturnLogError(ret, "Remove for %d failed with %d", it->first, ret); - - this->RemoveCacheNode(Node); - return 0; - } -} - -std::string FileNode::GetName() -{ - return this->Name; -} - -std::string FileNode::GetPath() -{ - const char *path = this->Path.c_str(); - if (strncmp(path, "\x06root-", 6) == 0) /* FIXME: deduce the index */ - { - path += 6; - while (*path != '\0' && *path != '\x06') - path++; - if (*path == '\x06') - path++; - } - else - return this->Path; - - if (path[0] == '\0') - return std::string(this->fsi->RootName); - return std::string(path); -} diff --git a/Kernel/storage/virtual.cpp b/Kernel/storage/virtual.cpp deleted file mode 100644 index 41b11fa7..00000000 --- a/Kernel/storage/virtual.cpp +++ /dev/null @@ -1,257 +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 - -#include -#include -#include - -#include "../kernel.h" - -namespace vfs -{ - /* maj = 0 - min: - 0 - - 1 - /proc/self - ... - */ - - int __vfs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) - { - vfsInode *Parent = (vfsInode *)_Parent; - - if (!S_ISDIR(Parent->Node.Mode)) - return -ENOTDIR; - - assert(Parent->Node.Flags & I_FLAG_MOUNTPOINT); - - if (Parent->Children.empty()) - return -ENOENT; - - off_t offset = 0; - for (const auto &Root : Parent->Children) - { - char rootName[128]{}; - snprintf(rootName, sizeof(rootName), "\x06root-%ld\x06", offset); - - if (strcmp(rootName, Name) == 0) - { - *Result = Root; - return 0; - } - offset++; - } - - return -ENOENT; - } - - int __vfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result) - { - assert(Parent != nullptr); - assert(!"Not implemented"); - } - - /* This implementation is used internally by the kernel, so no "." & ".." */ - __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) - { - debug("_Node->GetMinor() != 0"); - return -ENOENT; - } - - assert(_Node->Flags & I_FLAG_MOUNTPOINT); - - fixme("maybe wrong implementation of readdir"); - - size_t totalSize = 0; - off_t entriesSkipped = 0; - struct kdirent *ent = nullptr; - vfsInode *Node = (vfsInode *)_Node; - off_t entries = 0; - for (const auto &Root : Node->Children) - { - if (entries >= Entries) - break; - - uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("root") + 1); - - if (Offset > entriesSkipped) - { - entriesSkipped++; - continue; - } - - if (totalSize + reclen >= Size) - break; - - ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); - ent->d_ino = Root->Index; - ent->d_off = Root->Offset; - ent->d_reclen = reclen; - ent->d_type = IFTODT(Root->Mode); - strncpy(ent->d_name, "root", strlen("root")); - - totalSize += reclen; - entries++; - } - - 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; - } - - ssize_t __vfs_ReadLink(struct Inode *Node, char *Buffer, size_t Size) - { - switch (Node->GetMinor()) - { - case 1: - { - /* FIXME: https://github.com/torvalds/linux/blob/c942a0cd3603e34dd2d7237e064d9318cb7f9654/fs/proc/self.c#L11 - https://lxr.linux.no/#linux+v3.2.9/fs/proc/base.c#L2482 */ - - int ret = snprintf(Buffer, Size, "/proc/%d", thisProcess->ID); - debug("ReadLink: %s (%d bytes)", Buffer, ret); - return ret; - } - default: - return -ENOENT; - } - } - - void Virtual::Initialize() - { - SmartLock(VirtualLock); - - trace("Initializing virtual file system..."); - uint32_t iFlags = I_FLAG_CACHE_KEEP; - - /* d rwx rwx rwx */ - mode_t mode = S_IRWXU | - S_IRWXG | - S_IRWXO | - S_IFDIR; - FileNode *proc = this->ForceCreate(this->GetRoot(0), "proc", mode); - FileNode *var = this->ForceCreate(this->GetRoot(0), "var", mode); - FileNode *log = this->ForceCreate(var, "log", mode); - proc->Node->Flags = iFlags; - log->Node->Flags = iFlags; - - /* l rwx rwx rwx */ - mode = S_IRWXU | - S_IRWXG | - S_IRWXO | - S_IFLNK; - FileNode *self = this->ForceCreate(proc, "self", mode); - self->Node->Device = FileSystemRoots->Node.Device; - self->Node->SetDevice(0, 1); - self->Node->Flags = iFlags; - } - - 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); - - FileSystemRoots = new vfsInode; - FileSystemRoots->Node.Index = -1; - - FileSystemRoots->Node.Mode = S_IRWXU | - S_IRWXG | - S_IROTH | S_IXOTH | - S_IFDIR; - - 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->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.ReadDir = __vfs_Readdir; - fsi->Ops.ReadLink = __vfs_ReadLink; - - FileSystemRoots->Node.Device = this->RegisterFileSystem(fsi, &FileSystemRoots->Node); - FileSystemRoots->Node.SetDevice(0, 0); - } - - Virtual::~Virtual() - { - } -} diff --git a/Kernel/subsystem/linux/init.cpp b/Kernel/subsystem/linux/init.cpp index 81a5730b..faaddb3a 100644 --- a/Kernel/subsystem/linux/init.cpp +++ b/Kernel/subsystem/linux/init.cpp @@ -15,45 +15,88 @@ along with Fennix Kernel. If not, see . */ -#include +#include #include "../../kernel.h" +#include +#include namespace Subsystem::Linux { bool Initialized = false; + void __CreateStubRoot() + { + Node root = fs->GetRoot(0); + Node nmnt = fs->Lookup(root, "/mnt"); + assert(MountAndRootRAMFS(nmnt, "linux", 1)); + Node linux = fs->GetRoot(1); + + Node bin = fs->Create(linux, "bin", 0755); + Node boot = fs->Create(linux, "boot", 0755); + Node dev = fs->Create(linux, "dev", 0755); + Node etc = fs->Create(linux, "etc", 0755); + Node home = fs->Create(linux, "home", 0755); + Node lib = fs->Create(linux, "lib", 0755); + Node lib64 = fs->Create(linux, "lib64", 0755); + Node media = fs->Create(linux, "media", 0755); + Node mnt = fs->Create(linux, "mnt", 0755); + Node opt = fs->Create(linux, "opt", 0755); + Node proc = fs->Create(linux, "proc", 0755); + + UNUSED(bin); + UNUSED(boot); + UNUSED(dev); + UNUSED(etc); + UNUSED(home); + UNUSED(lib); + UNUSED(lib64); + UNUSED(media); + UNUSED(mnt); + UNUSED(opt); + UNUSED(proc); + } + void InitializeSubSystem() { if (fs->RootExists(1) == false) { - FileNode *nmnt = fs->GetByPath("/mnt", fs->GetRoot(0)); - assert(MountRAMFS(nmnt, "linux", 1)); - FileNode *linux = fs->GetRoot(1); + Node root = fs->GetRoot(0); + Node cfg = fs->Lookup(root, "/sys/cfg/subsystem/linux"); + if (cfg) + { + struct kstat st; + fs->Stat(cfg, &st); - FileNode *bin = fs->ForceCreate(linux, "bin", 0755); - FileNode *boot = fs->ForceCreate(linux, "boot", 0755); - FileNode *dev = fs->ForceCreate(linux, "dev", 0755); - FileNode *etc = fs->ForceCreate(linux, "etc", 0755); - FileNode *home = fs->ForceCreate(linux, "home", 0755); - FileNode *lib = fs->ForceCreate(linux, "lib", 0755); - FileNode *lib64 = fs->ForceCreate(linux, "lib64", 0755); - FileNode *media = fs->ForceCreate(linux, "media", 0755); - FileNode *mnt = fs->ForceCreate(linux, "mnt", 0755); - FileNode *opt = fs->ForceCreate(linux, "opt", 0755); - FileNode *proc = fs->ForceCreate(linux, "proc", 0755); + std::unique_ptr buf(new char[st.Size]); + fs->Read(cfg, buf.get(), st.Size, 0); - UNUSED(bin); - UNUSED(boot); - UNUSED(dev); - UNUSED(etc); - UNUSED(home); - UNUSED(lib); - UNUSED(lib64); - UNUSED(media); - UNUSED(mnt); - UNUSED(opt); - UNUSED(proc); + ini_t *ini = ini_load(buf.get(), NULL); + int section = ini_find_section(ini, "rootfs", NULL); + int pathIdx = ini_find_property(ini, section, "path", NULL); + const char *uPath = ini_property_value(ini, section, pathIdx); + debug("path=%s", uPath); + ini_destroy(ini); + + if (fs->Lookup(root, uPath) != false) + { + root = fs->Lookup(root, uPath); + + // if (TestAndInitializeUSTAR(moduleAddress, moduleSize, 0)) + // { + // } + } + else + { + warn("Couldn't find rootfs path %s", uPath); + __CreateStubRoot(); + } + } + else + { + warn("Couldn't open /sys/cfg/subsystem/linux"); + __CreateStubRoot(); + } } } } diff --git a/Kernel/subsystem/linux/syscall.cpp b/Kernel/subsystem/linux/syscall.cpp index 1ca1a384..9d4804a1 100644 --- a/Kernel/subsystem/linux/syscall.cpp +++ b/Kernel/subsystem/linux/syscall.cpp @@ -816,7 +816,7 @@ static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode) if (flags & 0200000 /* O_DIRECTORY */) { - FileNode *node = fs->GetByPath(pPathname, pcb->CWD); + Node node = fs->Lookup(pcb->CWD, pPathname); if (node == nullptr) { debug("Couldn't find %s", pPathname); @@ -1313,7 +1313,7 @@ static int linux_access(SysFrm *, const char *pathname, int mode) debug("access(%s, %d)", (char *)pPathname, mode); - if (!fs->PathExists(pPathname, pcb->CWD)) + if (!fs->Lookup(pcb->CWD, pPathname)) return -linux_ENOENT; stub; @@ -1717,7 +1717,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn safeEnvp[i + 1] = nullptr; } - FileNode *file = fs->GetByPath(pPathname, pcb->CWD); + Node file = fs->Lookup(pcb->CWD, pPathname); if (!file) { @@ -1726,7 +1726,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn } char shebangMagic[2]{}; - file->Read((uint8_t *)shebangMagic, 2, 0); + fs->Read(file, (uint8_t *)shebangMagic, 2, 0); if (shebangMagic[0] == '#' && shebangMagic[1] == '!') { @@ -1740,7 +1740,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn while (true) { char c; - if (file->Read((uint8_t *)&c, 1, shebangOffset) == 0) + if (fs->Read(file, (uint8_t *)&c, 1, shebangOffset) == 0) break; if (c == '\n' || shebangLength == shebangLengthMax) break; @@ -1870,7 +1870,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn cwk_path_get_basename(pPathname, &baseName, nullptr); pcb->Rename(baseName); - pcb->SetWorkingDirectory(file->Parent); + pcb->SetWorkingDirectory(fs->Convert(file->Parent)); pcb->SetExe(pPathname); Tasking::Task *ctx = pcb->GetContext(); @@ -2208,14 +2208,15 @@ static int linux_uname(SysFrm *, struct utsname *buf) #endif }; - FileNode *rn = fs->GetByPath("/sys/cfg/cross/linux", pcb->Info.RootNode); + Node root = fs->GetRoot(0); + Node rn = fs->Lookup(root, "/sys/cfg/subsystem/linux"); if (rn) { - struct kstat st{}; - rn->Stat(&st); + struct kstat st; + fs->Stat(rn, &st); char *sh = new char[st.Size]; - rn->Read(sh, st.Size, 0); + fs->Read(rn, sh, st.Size, 0); ini_t *ini = ini_load(sh, NULL); int section = ini_find_section(ini, "uname", NULL); @@ -2250,7 +2251,7 @@ static int linux_uname(SysFrm *, struct utsname *buf) delete[] sh; } else - warn("Couldn't open /sys/cfg/cross/linux"); + warn("Couldn't open /sys/cfg/subsystem/linux"); memcpy(pBuf, &uname, sizeof(struct utsname)); return 0; @@ -2360,7 +2361,7 @@ static int linux_chdir(SysFrm *, const char *path) if (!pPath) return -linux_EFAULT; - FileNode *n = fs->GetByPath(pPath, pcb->CWD); + Node n = fs->Lookup(pcb->CWD, pPath); if (!n) return -linux_ENOENT; @@ -2378,8 +2379,8 @@ static int linux_fchdir(SysFrm *, int fd) if (it == fdt->FileMap.end()) return -linux_EBADF; - pcb->SetWorkingDirectory(it->second.Node); - debug("Changed cwd to \"%s\"", it->second.Node->GetPath().c_str()); + pcb->SetWorkingDirectory(it->second.node); + debug("Changed cwd to \"%s\"", it->second.node->GetPath().c_str()); return 0; } @@ -2395,7 +2396,7 @@ static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode) mode &= ~pcb->FileCreationMask & 0777; - FileNode *n = fs->Create(pcb->CWD, pPathname, mode); + Node n = fs->Create(pcb->CWD, pPathname, mode); if (!n) return -linux_EEXIST; return 0; @@ -2432,13 +2433,13 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname, ReturnLogError(-linux_EBADF, "Invalid fd %d", fd); vfs::FileDescriptorTable::Fildes &fildes = it->second; - FileNode *node = fildes.Node; + Node node = fildes.node; fdt->usr_close(fd); if (!node->IsSymbolicLink()) return -linux_EINVAL; - return ConvertErrnoToLinux(node->ReadLink(pBuf, bufsiz)); + return ConvertErrnoToLinux(fs->ReadLink(node, pBuf, bufsiz)); } static int linux_fchmod(SysFrm *, int fd, mode_t mode) @@ -2480,7 +2481,7 @@ static int linux_chmod(SysFrm *sf, const char *pathname, mode_t mode) if (pPathname == nullptr) return -linux_EFAULT; - FileNode *node = fs->GetByPath(pPathname, pcb->CWD); + Node node = fs->Lookup(pcb->CWD, pPathname); if (!node) return -linux_ENOENT; @@ -3114,7 +3115,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *, } vfs::FileDescriptorTable::Fildes &fildes = it->second; - if (!fildes.Node->IsDirectory()) + if (!fildes.node->IsDirectory()) { debug("Not a directory"); return -ENOTDIR; @@ -3138,8 +3139,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *, #endif /* The structs are the same, no need for conversion. */ - ssize_t ret = fildes.Node->ReadDir((struct kdirent *)pDirp, count, fildes.Offset, - count / sizeof(kdirent)); + ssize_t ret = fs->ReadDirectory(fildes.node, (struct kdirent *)pDirp, count, fildes.Offset, count / sizeof(kdirent)); if (ret > 0) fildes.Offset += ret; @@ -3324,7 +3324,7 @@ static int linux_openat(SysFrm *, int dirfd, const char *pathname, int flags, mo if (dirfd == linux_AT_FDCWD) { - FileNode *absoluteNode = fs->GetByPath(pPathname, pcb->CWD); + Node absoluteNode = fs->Lookup(pcb->CWD, pPathname); if (!absoluteNode) return -linux_ENOENT; @@ -3373,7 +3373,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname, case linux_AT_FDCWD: { debug("dirfd is AT_FDCWD for \"%s\"", pPathname); - FileNode *node = fs->GetByPath(pPathname, pcb->CWD); + Node node = fs->Lookup(pcb->CWD, pPathname); if (!node) return -linux_ENOENT; @@ -3390,7 +3390,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname, ReturnLogError(-linux_EBADF, "Invalid fd %d", dirfd); vfs::FileDescriptorTable::Fildes &fildes = it->second; - FileNode *node = fs->GetByPath(pPathname, fildes.Node); + Node node = fs->Lookup(fildes.node, pPathname); debug("node: %s", node->GetPath().c_str()); if (!node) return -linux_ENOENT; diff --git a/Kernel/subsystem/windows/init.cpp b/Kernel/subsystem/windows/init.cpp index 56ca1365..43fa881e 100644 --- a/Kernel/subsystem/windows/init.cpp +++ b/Kernel/subsystem/windows/init.cpp @@ -15,7 +15,7 @@ along with Fennix Kernel. If not, see . */ -#include +#include #include "../../kernel.h" @@ -23,25 +23,30 @@ namespace Subsystem::Windows { bool Initialized = false; + void __CreateStubRoot() + { + Node root = fs->GetRoot(0); + Node nmnt = fs->Lookup(root, "/mnt"); + assert(MountAndRootRAMFS(nmnt, "windows", 2)); + Node win = fs->GetRoot(2); + + Node windows = fs->Create(win, "Windows", 0755); + Node programFiles = fs->Create(windows, "Program Files", 0755); + Node programFilesX86 = fs->Create(windows, "Program Files (x86)", 0755); + Node programData = fs->Create(windows, "ProgramData", 0755); + Node users = fs->Create(windows, "Users", 0755); + + UNUSED(windows); + UNUSED(programFiles); + UNUSED(programFilesX86); + UNUSED(programData); + UNUSED(users); + } + void InitializeSubSystem() { if (fs->RootExists(2) == false) { - FileNode *nmnt = fs->GetByPath("/mnt", fs->GetRoot(0)); - assert(MountRAMFS(nmnt, "windows", 2)); - FileNode *win = fs->GetRoot(2); - - FileNode *windows = fs->ForceCreate(win, "Windows", 0755); - FileNode *programFiles = fs->ForceCreate(windows, "Program Files", 0755); - FileNode *programFilesX86 = fs->ForceCreate(windows, "Program Files (x86)", 0755); - FileNode *programData = fs->ForceCreate(windows, "ProgramData", 0755); - FileNode *users = fs->ForceCreate(windows, "Users", 0755); - - UNUSED(windows); - UNUSED(programFiles); - UNUSED(programFilesX86); - UNUSED(programData); - UNUSED(users); } } } diff --git a/Kernel/syscalls/native.cpp b/Kernel/syscalls/native.cpp index 0b4912cd..082158d8 100644 --- a/Kernel/syscalls/native.cpp +++ b/Kernel/syscalls/native.cpp @@ -109,7 +109,7 @@ static int sys_open(SysFrm *Frame, const char *pathname, int flags, mode_t mode) if (flags & 0200000 /* O_DIRECTORY */) { - FileNode *node = fs->GetByPath(pPathname, pcb->CWD); + Node node = fs->Lookup(pcb->CWD, pPathname); if (node == nullptr) { debug("Couldn't find %s", pPathname); @@ -150,7 +150,7 @@ static int sys_access(SysFrm *Frame, const char *pathname, int mode) debug("access(%s, %d)", (char *)pPathname, mode); - if (!fs->PathExists(pPathname, pcb->CWD)) + if (!fs->Lookup(pcb->CWD, pPathname)) return -ENOENT; stub; diff --git a/Kernel/tasking/process.cpp b/Kernel/tasking/process.cpp index d64d590b..7e2b530e 100644 --- a/Kernel/tasking/process.cpp +++ b/Kernel/tasking/process.cpp @@ -95,34 +95,34 @@ namespace Tasking strcpy((char *)this->Name, name); } - void PCB::SetWorkingDirectory(FileNode *node) + void PCB::SetWorkingDirectory(Node node) { - trace("Setting working directory of process %s to %#lx (%s)", - this->Name, node, node->Name.c_str()); - CWD = node; - FileNode *cwd = fs->GetByPath("cwd", ProcDirectory); + trace("Setting working directory of process %s", node->Name.c_str()); + this->CWD = node; + Node cwd = fs->Lookup(ProcDirectory, "cwd"); if (cwd) fs->Remove(cwd); - cwd = fs->CreateLink("cwd", ProcDirectory, node); + cwd = fs->CreateLink(ProcDirectory, "cwd", node); if (cwd == nullptr) error("Failed to create cwd link"); } void PCB::SetExe(const char *path) { - trace("Setting exe %s to %s", - this->Name, path); - Executable = fs->GetByPath(path, ProcDirectory); + trace("Setting exe %s to %s", this->Name, path); + + Executable = fs->Lookup(ProcDirectory, path); if (Executable->IsSymbolicLink()) { char buffer[512]; - Executable->ReadLink(buffer, sizeof(buffer)); - Executable = fs->GetByPath(buffer, Executable->Parent); + fs->ReadLink(Executable, buffer, sizeof(buffer)); + Executable = fs->Lookup(Executable->Parent, buffer); } - FileNode *exe = fs->GetByPath("exe", ProcDirectory); + + Node exe = fs->Lookup(ProcDirectory, "exe"); if (exe) fs->Remove(exe); - exe = fs->CreateLink("exe", ProcDirectory, path); + exe = fs->CreateLink(ProcDirectory, "exe", path); if (exe == nullptr) error("Failed to create exe link"); } @@ -155,7 +155,8 @@ namespace Tasking assert(ExecutionMode >= _ExecuteModeMin); assert(ExecutionMode <= _ExecuteModeMax); - FileNode *procDir = fs->GetByPath("/proc", nullptr); + Node root = fs->GetRoot(0); + Node procDir = fs->Lookup(root, "/proc"); assert(procDir != nullptr); /* d r-x r-x r-x */ diff --git a/Kernel/tasking/task.cpp b/Kernel/tasking/task.cpp index 955e3ba3..87342ec2 100644 --- a/Kernel/tasking/task.cpp +++ b/Kernel/tasking/task.cpp @@ -246,23 +246,222 @@ namespace Tasking debug("Tasking Started"); } + struct TaskNode : public Inode + { + kstat Stat; + Inode *Parent; + std::string Name; + std::vector Children; + }; + + int __task_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result) + { + return -ENOSYS; + } + + int __task_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result) + { + TaskNode *p = (TaskNode *)Parent; + + if (!S_ISDIR(p->Mode)) + return -ENOTDIR; + + TaskNode *newNode = new TaskNode; + newNode->Parent = p; + newNode->Name = Name; + newNode->Mode = Mode; + p->Children.push_back(newNode); + *Result = newNode; + return 0; + } + + ssize_t __task_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) + { + return -ENOSYS; + } + + ssize_t __task_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) + { + return -ENOSYS; + } + + __no_sanitize("alignment") ssize_t __task_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) + { + auto node = (TaskNode *)_Node; + off_t realOffset = Offset; + size_t totalSize = 0; + uint16_t reclen = 0; + struct kdirent *ent = nullptr; + + if (!S_ISDIR(node->Mode)) + return -ENOTDIR; + + 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->Index; + ent->d_off = 0; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, "."); + totalSize += reclen; + Offset++; + } + + if (Offset == 1) + { + reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1); + if (totalSize + reclen > Size) + return totalSize; + + ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); + ent->d_ino = node->Parent ? node->Parent->Index : 0; + ent->d_off = 1; + ent->d_reclen = reclen; + ent->d_type = DT_DIR; + strcpy(ent->d_name, ".."); + totalSize += reclen; + Offset++; + } + + off_t entryIndex = 0; + for (const auto &var : node->Children) + { + if (entryIndex + 2 < realOffset) + { + entryIndex++; + continue; + } + if (Entries && entryIndex >= 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->Index; + ent->d_off = entryIndex + 2; + ent->d_reclen = reclen; + ent->d_type = IFTODT(var->Mode); + strcpy(ent->d_name, var->Name.c_str()); + totalSize += reclen; + entryIndex++; + } + + if (totalSize + offsetof(struct kdirent, d_name) + 1 > 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; + } + + int __task_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result) + { + return -ENOSYS; + } + + ssize_t __task_ReadLink(Inode *Node, char *Buffer, size_t Size) + { + switch (Node->GetMajor()) + { + case 0: + { + switch (Node->GetMinor()) + { + case 0: + { + /* FIXME: https://github.com/torvalds/linux/blob/c942a0cd3603e34dd2d7237e064d9318cb7f9654/fs/proc/self.c#L11 + https://lxr.linux.no/#linux+v3.2.9/fs/proc/base.c#L2482 */ + + int ret = snprintf(Buffer, Size, "/proc/%d", thisProcess->ID); + debug("ReadLink: %s (%d bytes)", Buffer, ret); + return ret; + } + default: + return -ENOENT; + } + } + default: + return -ENOENT; + } + } + + int __task_Stat(struct Inode *Node, kstat *Stat) + { + TaskNode *node = (TaskNode *)Node; + *Stat = node->Stat; + return 0; + } + + int __task_AllocateInode(struct FileSystemInfo *, struct Inode **Result) + { + TaskNode *ret = new TaskNode; + *Result = (Inode *)ret; + return 0; + } + + int __task_DeleteInode(struct FileSystemInfo *, struct Inode *Node) + { + delete Node; + return 0; + } + Task::Task(const IP EntryPoint) { + Node root = fs->GetRoot(0); + FileSystemInfo *fsi = new FileSystemInfo; + fsi->Name = "procfs"; + fsi->SuperOps.AllocateInode = __task_AllocateInode; + fsi->SuperOps.DeleteInode = __task_DeleteInode; + fsi->Ops.Lookup = __task_Lookup; + fsi->Ops.Create = __task_Create; + fsi->Ops.Read = __task_Read; + fsi->Ops.Write = __task_Write; + fsi->Ops.ReadDir = __task_Readdir; + fsi->Ops.SymLink = __task_SymLink; + fsi->Ops.ReadLink = __task_ReadLink; + fsi->Ops.Stat = __task_Stat; + + /* d rwx rwx rwx */ + mode_t mode = S_IRWXU | + S_IRWXG | + S_IRWXO | + S_IFDIR; + TaskNode *inode = new TaskNode; + inode->Device = fs->RegisterFileSystem(fsi); + inode->Mode = mode; + Node proc = fs->Mount(root, inode, "proc", fsi); + // proc->fsi = fsi; + // inode->Parent = root->inode; + // inode->Name = "proc"; + + /* l rwx rwx rwx */ + mode = S_IRWXU | + S_IRWXG | + S_IRWXO | + S_IFLNK; + Node self = fs->Create(proc, "self", mode); + self->inode->Device = inode->Device; + self->inode->SetDevice(0, 0); + /* I don't know if this is the best way to do this. */ Scheduler::Custom *custom_sched = new Scheduler::Custom(this); Scheduler::Base *sched = r_cst(Scheduler::Base *, custom_sched); __sched_ctx = custom_sched; Scheduler = sched; - KernelProcess = CreateProcess(nullptr, "Kernel", - TaskExecutionMode::Kernel, true); - KernelProcess->PageTable = KernelPageTable; - TCB *kthrd = CreateThread(KernelProcess, EntryPoint, - nullptr, nullptr, - std::vector(), GetKArch()); + KernelProcess = CreateProcess(nullptr, "Kernel", Kernel, true, 0, 0); + TCB *kthrd = CreateThread(KernelProcess, EntryPoint, nullptr, nullptr, {}, GetKArch()); kthrd->Rename("Main Thread"); - debug("Created Kernel Process: %s and Thread: %s", - KernelProcess->Name, kthrd->Name); + debug("Created Kernel Process: %s and Thread: %s", KernelProcess->Name, kthrd->Name); if (!CPU::Interrupts(CPU::Check)) { diff --git a/Kernel/tasking/thread.cpp b/Kernel/tasking/thread.cpp index ed29bdf9..d9eeb918 100644 --- a/Kernel/tasking/thread.cpp +++ b/Kernel/tasking/thread.cpp @@ -17,7 +17,7 @@ #include -#include +#include #include #include #include diff --git a/Kernel/tests/macros.cpp b/Kernel/tests/macros.cpp index 90f9c2fe..4dff383d 100644 --- a/Kernel/tests/macros.cpp +++ b/Kernel/tests/macros.cpp @@ -18,11 +18,11 @@ #ifdef DEBUG #include -#include +#include #include #include #include -#include +#include #include #include diff --git a/Kernel/tests/readdir.cpp b/Kernel/tests/readdir.cpp new file mode 100644 index 00000000..a9cb11b5 --- /dev/null +++ b/Kernel/tests/readdir.cpp @@ -0,0 +1,94 @@ +/* + 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 "../kernel.h" + +#ifdef DEBUG + +void TestReadDirectory(Node &Target) +{ + const size_t bufLen = 4096; + std::unique_ptr buf(new uint8_t[bufLen]); + off_t off = 0; + off_t max = LONG_MAX; + + KPrint("Listing directory: \x1b[1;36m%s\x1b[0m", Target->Name.c_str()); + + while (true) + { + ssize_t bytes = fs->ReadDirectory(Target, (kdirent *)buf.get(), bufLen, off, max); + if (bytes < 0) + { + KPrint("ReadDirectory returned error: %d", bytes); + break; + } + if (bytes == 0) + break; + + ssize_t Pos = 0; + while (Pos < bytes) + { + kdirent *Entry = (kdirent *)(buf.get() + Pos); + if (Entry->d_reclen == 0) + { + KPrint("Entry with zero length detected at offset %ld!", off + Pos); + break; + } + + KPrint("name=\"%s\" inode=%lu type=%u reclen=%u", Entry->d_name, Entry->d_ino, Entry->d_type, Entry->d_reclen); + + Pos += Entry->d_reclen; + } + off += bytes; + } +} + +void readdir_sanity_tests() +{ + Node root = fs->GetRoot(0); + Node t0 = fs->Lookup(root, "/"); + Node t1 = fs->Lookup(root, "/dev"); + Node t2 = fs->Lookup(root, "/home"); + Node t3 = fs->Lookup(root, "/var"); + Node t4 = fs->Lookup(root, "/tmp"); + + KPrint("TEST /"); + TestReadDirectory(t0); + TaskManager->Sleep(2000); + + KPrint("TEST /dev"); + TestReadDirectory(t1); + TaskManager->Sleep(2000); + + KPrint("TEST /home"); + TestReadDirectory(t2); + TaskManager->Sleep(2000); + + KPrint("TEST /var"); + TestReadDirectory(t3); + TaskManager->Sleep(2000); + + KPrint("TEST /tmp"); + TestReadDirectory(t4); + TaskManager->Sleep(2000); + + CPU::Stop(); +} + +#endif // DEBUG diff --git a/Kernel/tests/t.h b/Kernel/tests/t.h index dafb7a33..08d4d5e6 100644 --- a/Kernel/tests/t.h +++ b/Kernel/tests/t.h @@ -20,14 +20,14 @@ #ifdef DEBUG #include -#include +#include void Test_stl(); void TestMemoryAllocation(); void tasking_test_fb(); void tasking_test_mutex(); void TaskMgr(); -void TreeFS(FileNode *node, int Depth); +void TreeFS(Node node, int Depth); void TaskHeartbeat(); void StressKernel(); void coroutineTest(); diff --git a/Kernel/tests/treefs.cpp b/Kernel/tests/treefs.cpp index e498c218..0a3646a6 100644 --- a/Kernel/tests/treefs.cpp +++ b/Kernel/tests/treefs.cpp @@ -21,7 +21,7 @@ #include "../kernel.h" -void TreeFS(FileNode *node, int Depth) +void TreeFS(Node node, int Depth) { return; // for (auto Chld : node->GetChildren(true)) diff --git a/Kernel/tty/ptmx.cpp b/Kernel/tty/ptmx.cpp index 62c3f01b..05420316 100644 --- a/Kernel/tty/ptmx.cpp +++ b/Kernel/tty/ptmx.cpp @@ -16,7 +16,7 @@ */ #include -#include +#include #include #include diff --git a/Kernel/tty/vt.cpp b/Kernel/tty/vt.cpp index a3285f42..0ec8bde9 100644 --- a/Kernel/tty/vt.cpp +++ b/Kernel/tty/vt.cpp @@ -17,7 +17,7 @@ #include -#include +#include #include #include #include