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