mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-25 22:14:37 +00:00
940 lines
24 KiB
C++
940 lines
24 KiB
C++
/*
|
|
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 "../../kernel.h"
|
|
#include "../../driver.h"
|
|
|
|
// #define DEBUG_API
|
|
|
|
#ifdef DEBUG_API
|
|
#define dbg_api(Format, ...) function(Format, ##__VA_ARGS__)
|
|
#else
|
|
#define dbg_api(Format, ...)
|
|
#endif
|
|
|
|
using enum PCI::PCICommands;
|
|
|
|
#define VMWARE_MAGIC 0x564D5868 /* hXMV */
|
|
#define VMWARE_PORT 0x5658
|
|
#define CMD_GETVERSION 0xA
|
|
|
|
namespace Driver
|
|
{
|
|
int RegisterFunction(dev_t MajorID, void *Function, __driverRegFunc Type)
|
|
{
|
|
dbg_api("%d, %#lx, %d", MajorID, (uintptr_t)Function, Type);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
auto itr = Drivers.find(MajorID);
|
|
if (itr == Drivers.end())
|
|
return -EINVAL;
|
|
|
|
DriverObject *drv = &itr->second;
|
|
|
|
switch (Type)
|
|
{
|
|
case _drf_Entry:
|
|
drv->Entry = (int (*)())Function;
|
|
debug("Entry %#lx for %s", (uintptr_t)Function, drv->Path);
|
|
break;
|
|
case _drf_Final:
|
|
drv->Final = (int (*)())Function;
|
|
debug("Finalize %#lx for %s", (uintptr_t)Function, drv->Path);
|
|
break;
|
|
case _drf_Panic:
|
|
drv->Panic = (int (*)())Function;
|
|
debug("Panic %#lx for %s", (uintptr_t)Function, drv->Path);
|
|
break;
|
|
case _drf_Probe:
|
|
drv->Probe = (int (*)())Function;
|
|
debug("Probe %#lx for %s", (uintptr_t)Function, drv->Path);
|
|
break;
|
|
default:
|
|
assert(!"Invalid driver function type");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int GetDriverInfo(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License)
|
|
{
|
|
dbg_api("%d, %s, %s, %s, %s, %s", MajorID, Name, Description, Author, Version, License);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
auto itr = Drivers.find(MajorID);
|
|
if (itr == Drivers.end())
|
|
return -EINVAL;
|
|
|
|
DriverObject *drv = &itr->second;
|
|
|
|
strncpy(drv->Name, Name, sizeof(drv->Name));
|
|
strncpy(drv->Description, Description, sizeof(drv->Description));
|
|
strncpy(drv->Author, Author, sizeof(drv->Author));
|
|
strncpy(drv->Version, Version, sizeof(drv->Version));
|
|
strncpy(drv->License, License, sizeof(drv->License));
|
|
return 0;
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
int RegisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler)
|
|
{
|
|
dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
auto itr = Drivers.find(MajorID);
|
|
if (itr == Drivers.end())
|
|
return -EINVAL;
|
|
|
|
DriverObject *drv = &itr->second;
|
|
|
|
if (drv->InterruptHandlers->contains(IRQ))
|
|
return -EEXIST;
|
|
|
|
Interrupts::AddHandler((void (*)(CPU::TrapFrame *))Handler, IRQ);
|
|
drv->InterruptHandlers->insert(std::pair<uint8_t, void *>(IRQ, Handler));
|
|
return 0;
|
|
}
|
|
|
|
int OverrideInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler)
|
|
{
|
|
dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler);
|
|
|
|
debug("Overriding IRQ %d with %#lx", IRQ, Handler);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
foreach (auto &var in Drivers)
|
|
{
|
|
DriverObject *drv = &var.second;
|
|
|
|
foreach (auto &ih in * drv->InterruptHandlers)
|
|
{
|
|
if (ih.first == IRQ)
|
|
{
|
|
debug("Removing IRQ %d: %#lx for %s", IRQ, (uintptr_t)ih.second, drv->Path);
|
|
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))ih.second, IRQ);
|
|
drv->InterruptHandlers->erase(IRQ);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return RegisterInterruptHandler(MajorID, IRQ, Handler);
|
|
}
|
|
|
|
int UnregisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler)
|
|
{
|
|
dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
auto itr = Drivers.find(MajorID);
|
|
if (itr == Drivers.end())
|
|
return -EINVAL;
|
|
|
|
DriverObject *drv = &itr->second;
|
|
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, IRQ);
|
|
drv->InterruptHandlers->erase(IRQ);
|
|
return 0;
|
|
}
|
|
|
|
int UnregisterAllInterruptHandlers(dev_t MajorID, void *Handler)
|
|
{
|
|
dbg_api("%d, %#lx", MajorID, Handler);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
auto itr = Drivers.find(MajorID);
|
|
if (itr == Drivers.end())
|
|
return -EINVAL;
|
|
|
|
DriverObject *drv = &itr->second;
|
|
foreach (auto &i in * drv->InterruptHandlers)
|
|
{
|
|
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, i.first);
|
|
debug("Removed IRQ %d: %#lx for %s", i.first, (uintptr_t)Handler, drv->Path);
|
|
}
|
|
drv->InterruptHandlers->clear();
|
|
return 0;
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
dev_t RegisterInputDevice(dev_t MajorID, DeviceDriverType Type)
|
|
{
|
|
dbg_api("%d, %d", MajorID, Type);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_Keyboard:
|
|
return DriverManager->InputKeyboardDev->Register(MajorID);
|
|
case ddt_Mouse:
|
|
return DriverManager->InputMouseDev->Register(MajorID);
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid input device type");
|
|
}
|
|
}
|
|
|
|
int UnregisterInputDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
|
{
|
|
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_Keyboard:
|
|
return DriverManager->InputKeyboardDev->Unregister(MajorID, MinorID);
|
|
case ddt_Mouse:
|
|
return DriverManager->InputMouseDev->Unregister(MajorID, MinorID);
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid input device type");
|
|
}
|
|
}
|
|
|
|
int ReportKeyboardEvent(dev_t MajorID, dev_t MinorID, uint8_t ScanCode)
|
|
{
|
|
dbg_api("%d, %d, %d", MajorID, MinorID, ScanCode);
|
|
|
|
return DriverManager->InputKeyboardDev->ReportKeyEvent(MajorID, MinorID, ScanCode);
|
|
}
|
|
|
|
int ReportRelativeMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z)
|
|
{
|
|
dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z);
|
|
|
|
return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID,
|
|
Button.LeftButton, Button.RightButton, Button.MiddleButton,
|
|
Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8,
|
|
X, Y, Z, true);
|
|
}
|
|
|
|
int ReportAbsoluteMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z)
|
|
{
|
|
dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z);
|
|
|
|
return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID,
|
|
Button.LeftButton, Button.RightButton, Button.MiddleButton,
|
|
Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8,
|
|
X, Y, Z, false);
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
dev_t RegisterBlockDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl)
|
|
{
|
|
dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_SATA:
|
|
{
|
|
dev_t ret = DriverManager->BlockSATADev->Register(MajorID);
|
|
DriverManager->BlockSATADev->NewBlock(MajorID, ret,
|
|
(SlaveDeviceFile::drvOpen_t)Open,
|
|
(SlaveDeviceFile::drvClose_t)Close,
|
|
(SlaveDeviceFile::drvRead_t)Read,
|
|
(SlaveDeviceFile::drvWrite_t)Write,
|
|
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
|
return ret;
|
|
}
|
|
case ddt_ATA:
|
|
{
|
|
dev_t ret = DriverManager->BlockHDDev->Register(MajorID);
|
|
DriverManager->BlockHDDev->NewBlock(MajorID, ret,
|
|
(SlaveDeviceFile::drvOpen_t)Open,
|
|
(SlaveDeviceFile::drvClose_t)Close,
|
|
(SlaveDeviceFile::drvRead_t)Read,
|
|
(SlaveDeviceFile::drvWrite_t)Write,
|
|
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
|
return ret;
|
|
}
|
|
case ddt_NVMe:
|
|
{
|
|
dev_t ret = DriverManager->BlockNVMeDev->Register(MajorID);
|
|
DriverManager->BlockNVMeDev->NewBlock(MajorID, ret,
|
|
(SlaveDeviceFile::drvOpen_t)Open,
|
|
(SlaveDeviceFile::drvClose_t)Close,
|
|
(SlaveDeviceFile::drvRead_t)Read,
|
|
(SlaveDeviceFile::drvWrite_t)Write,
|
|
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
|
return ret;
|
|
}
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid storage device type");
|
|
}
|
|
}
|
|
|
|
int UnregisterBlockDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
|
{
|
|
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_SATA:
|
|
return DriverManager->BlockSATADev->Unregister(MajorID, MinorID);
|
|
case ddt_ATA:
|
|
return DriverManager->BlockHDDev->Unregister(MajorID, MinorID);
|
|
case ddt_NVMe:
|
|
return DriverManager->BlockNVMeDev->Unregister(MajorID, MinorID);
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid storage device type");
|
|
}
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
dev_t RegisterAudioDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl)
|
|
{
|
|
dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_Audio:
|
|
{
|
|
dev_t ret = DriverManager->AudioDev->Register(MajorID);
|
|
DriverManager->AudioDev->NewAudio(MajorID, ret,
|
|
(SlaveDeviceFile::drvOpen_t)Open,
|
|
(SlaveDeviceFile::drvClose_t)Close,
|
|
(SlaveDeviceFile::drvRead_t)Read,
|
|
(SlaveDeviceFile::drvWrite_t)Write,
|
|
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
|
return ret;
|
|
}
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid audio device type");
|
|
}
|
|
}
|
|
|
|
int UnregisterAudioDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
|
{
|
|
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_Audio:
|
|
return DriverManager->AudioDev->Unregister(MajorID, MinorID);
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid audio device type");
|
|
}
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
dev_t RegisterNetDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl)
|
|
{
|
|
dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_Network:
|
|
{
|
|
dev_t ret = DriverManager->NetDev->Register(MajorID);
|
|
DriverManager->NetDev->NewNet(MajorID, ret,
|
|
(SlaveDeviceFile::drvOpen_t)Open,
|
|
(SlaveDeviceFile::drvClose_t)Close,
|
|
(SlaveDeviceFile::drvRead_t)Read,
|
|
(SlaveDeviceFile::drvWrite_t)Write,
|
|
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
|
return ret;
|
|
}
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid audio device type");
|
|
}
|
|
}
|
|
|
|
int UnregisterNetDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
|
{
|
|
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
|
|
|
switch (Type)
|
|
{
|
|
case ddt_Network:
|
|
return DriverManager->NetDev->Unregister(MajorID, MinorID);
|
|
/* ... */
|
|
default:
|
|
assert(!"Invalid audio device type");
|
|
}
|
|
}
|
|
|
|
int ReportNetworkPacket(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size)
|
|
{
|
|
dbg_api("%d, %d, %#lx, %d", MajorID, MinorID, Buffer, Size);
|
|
|
|
return DriverManager->NetDev->ReportNetworkPacket(MajorID, MinorID, Buffer, Size);
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
void d_KPrint(dev_t MajorID, const char *Format, va_list args)
|
|
{
|
|
dbg_api("%d %s, %#lx", MajorID, Format, args);
|
|
|
|
_KPrint(Format, args);
|
|
}
|
|
|
|
void KernelLog(dev_t MajorID, const char *Format, va_list args)
|
|
{
|
|
dbg_api("%d, %s, %#lx", MajorID, Format, args);
|
|
|
|
fctprintf(uart_wrapper, nullptr, "DRVER| %ld: ", MajorID);
|
|
vfctprintf(uart_wrapper, nullptr, Format, args);
|
|
uart_wrapper('\n', nullptr);
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
void *RequestPages(dev_t MajorID, size_t Pages)
|
|
{
|
|
dbg_api("%d, %d", MajorID, Pages);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
auto itr = Drivers.find(MajorID);
|
|
assert(itr != Drivers.end());
|
|
|
|
return itr->second.vma->RequestPages(Pages);
|
|
}
|
|
|
|
void FreePages(dev_t MajorID, void *Pointer, size_t Pages)
|
|
{
|
|
dbg_api("%d, %#lx, %d", MajorID, Pointer, Pages);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
auto itr = Drivers.find(MajorID);
|
|
assert(itr != Drivers.end());
|
|
|
|
itr->second.vma->FreePages(Pointer, Pages);
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
void AppendMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag)
|
|
{
|
|
dbg_api("%d, %#lx, %d", MajorID, Address, Flag);
|
|
|
|
Memory::Virtual vmm(KernelPageTable);
|
|
vmm.GetPTE(Address)->raw |= Flag;
|
|
}
|
|
|
|
void RemoveMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag)
|
|
{
|
|
dbg_api("%d, %#lx, %d", MajorID, Address, Flag);
|
|
|
|
Memory::Virtual vmm(KernelPageTable);
|
|
vmm.GetPTE(Address)->raw &= ~Flag;
|
|
}
|
|
|
|
void MapPages(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags)
|
|
{
|
|
dbg_api("%d, %#lx, %#lx, %d, %d", MajorID, PhysicalAddress, VirtualAddress, Pages, Flags);
|
|
|
|
Memory::Virtual vmm(KernelPageTable);
|
|
vmm.Map(VirtualAddress, PhysicalAddress, Pages, Flags);
|
|
}
|
|
|
|
void UnmapPages(dev_t MajorID, void *VirtualAddress, size_t Pages)
|
|
{
|
|
dbg_api("%d, %#lx, %d", MajorID, VirtualAddress, Pages);
|
|
|
|
Memory::Virtual vmm(KernelPageTable);
|
|
vmm.Unmap(VirtualAddress, Pages);
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
pid_t CreateKernelProcess(dev_t MajorID, const char *Name)
|
|
{
|
|
dbg_api("%d, %s", MajorID, Name);
|
|
|
|
Tasking::PCB *pcb = TaskManager->CreateProcess(nullptr,
|
|
Name, Tasking::System,
|
|
nullptr, true, 0, 0);
|
|
|
|
return pcb->ID;
|
|
}
|
|
|
|
pid_t CreateKernelThread(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument)
|
|
{
|
|
dbg_api("%d, %d, %s, %#lx, %#lx", MajorID, pId, Name, EntryPoint, Argument);
|
|
|
|
Tasking::PCB *parent = TaskManager->GetProcessByID(pId);
|
|
if (!parent)
|
|
return -EINVAL;
|
|
|
|
CriticalSection cs;
|
|
Tasking::TCB *tcb = TaskManager->CreateThread(parent, (Tasking::IP)EntryPoint);
|
|
if (Argument)
|
|
tcb->SYSV_ABI_Call((uintptr_t)Argument);
|
|
tcb->Rename(Name);
|
|
return tcb->ID;
|
|
}
|
|
|
|
int KillProcess(dev_t MajorID, pid_t pId, int ExitCode)
|
|
{
|
|
dbg_api("%d, %d, %d", MajorID, pId, ExitCode);
|
|
|
|
Tasking::PCB *pcb = TaskManager->GetProcessByID(pId);
|
|
if (!pcb)
|
|
return -EINVAL;
|
|
TaskManager->KillProcess(pcb, (Tasking::KillCode)ExitCode);
|
|
return 0;
|
|
}
|
|
|
|
int KillThread(dev_t MajorID, pid_t tId, int ExitCode)
|
|
{
|
|
dbg_api("%d, %d, %d", MajorID, tId, ExitCode);
|
|
|
|
Tasking::TCB *tcb = TaskManager->GetThreadByID(tId);
|
|
if (!tcb)
|
|
return -EINVAL;
|
|
TaskManager->KillThread(tcb, (Tasking::KillCode)ExitCode);
|
|
return 0;
|
|
}
|
|
|
|
void Yield(dev_t MajorID)
|
|
{
|
|
dbg_api("%d", MajorID);
|
|
|
|
TaskManager->Yield();
|
|
}
|
|
|
|
void Sleep(dev_t MajorID, uint64_t Milliseconds)
|
|
{
|
|
dbg_api("%d, %d", MajorID, Milliseconds);
|
|
|
|
TaskManager->Sleep(Milliseconds);
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
__PCIArray *GetPCIDevices(dev_t MajorID, uint16_t _Vendors[], uint16_t _Devices[])
|
|
{
|
|
dbg_api("%d, %#lx, %#lx", MajorID, _Vendors, _Devices);
|
|
|
|
std::unordered_map<dev_t, DriverObject> &Drivers =
|
|
DriverManager->GetDrivers();
|
|
|
|
auto itr = Drivers.find(MajorID);
|
|
if (itr == Drivers.end())
|
|
return nullptr;
|
|
|
|
std::list<uint16_t> VendorIDs;
|
|
for (int i = 0; _Vendors[i] != 0x0; i++)
|
|
VendorIDs.push_back(_Vendors[i]);
|
|
|
|
std::list<uint16_t> DeviceIDs;
|
|
for (int i = 0; _Devices[i] != 0x0; i++)
|
|
DeviceIDs.push_back(_Devices[i]);
|
|
|
|
std::list<PCI::PCIDevice> Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs);
|
|
if (Devices.empty())
|
|
return nullptr;
|
|
|
|
Memory::VirtualMemoryArea *vma = itr->second.vma;
|
|
__PCIArray *head = nullptr;
|
|
__PCIArray *array = nullptr;
|
|
|
|
foreach (auto &dev in Devices)
|
|
{
|
|
/* TODO: optimize memory allocation */
|
|
PCI::PCIDevice *dptr = (PCI::PCIDevice *)vma->RequestPages(TO_PAGES(sizeof(PCI::PCIDevice)));
|
|
memcpy(dptr, &dev, sizeof(PCI::PCIDevice));
|
|
|
|
__PCIArray *newArray = (__PCIArray *)vma->RequestPages(TO_PAGES(sizeof(__PCIArray)));
|
|
|
|
if (unlikely(head == nullptr))
|
|
{
|
|
head = newArray;
|
|
array = head;
|
|
}
|
|
else
|
|
{
|
|
array->Next = newArray;
|
|
array = newArray;
|
|
}
|
|
|
|
array->Device = dptr;
|
|
array->Next = nullptr;
|
|
|
|
debug("Found %02x.%02x.%02x: %04x:%04x",
|
|
dev.Bus, dev.Device, dev.Function,
|
|
dev.Header->VendorID, dev.Header->DeviceID);
|
|
}
|
|
|
|
return head;
|
|
}
|
|
|
|
void InitializePCI(dev_t MajorID, void *_Header)
|
|
{
|
|
dbg_api("%d, %#lx", MajorID, _Header);
|
|
|
|
PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header;
|
|
|
|
debug("Header Type: %d", Header->HeaderType);
|
|
switch (Header->HeaderType)
|
|
{
|
|
case 128:
|
|
warn("Unknown header type %d! Guessing PCI Header 0",
|
|
Header->HeaderType);
|
|
[[fallthrough]];
|
|
case 0: /* PCI Header 0 */
|
|
{
|
|
PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)Header;
|
|
|
|
uint32_t BAR[6];
|
|
size_t BARsSize[6];
|
|
|
|
BAR[0] = hdr0->BAR0;
|
|
BAR[1] = hdr0->BAR1;
|
|
BAR[2] = hdr0->BAR2;
|
|
BAR[3] = hdr0->BAR3;
|
|
BAR[4] = hdr0->BAR4;
|
|
BAR[5] = hdr0->BAR5;
|
|
|
|
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx",
|
|
BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
|
|
|
|
/* BARs Size */
|
|
for (short i = 0; i < 6; i++)
|
|
{
|
|
if (BAR[i] == 0)
|
|
continue;
|
|
|
|
size_t size;
|
|
if ((BAR[i] & 1) == 0) /* Memory Base */
|
|
{
|
|
hdr0->BAR0 = 0xFFFFFFFF;
|
|
size = hdr0->BAR0;
|
|
hdr0->BAR0 = BAR[i];
|
|
BARsSize[i] = size & (~15);
|
|
BARsSize[i] = ~BARsSize[i] + 1;
|
|
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF;
|
|
debug("BAR%d %#lx size: %d",
|
|
i, BAR[i], BARsSize[i]);
|
|
}
|
|
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
|
{
|
|
hdr0->BAR1 = 0xFFFFFFFF;
|
|
size = hdr0->BAR1;
|
|
hdr0->BAR1 = BAR[i];
|
|
BARsSize[i] = size & (~3);
|
|
BARsSize[i] = ~BARsSize[i] + 1;
|
|
BARsSize[i] = BARsSize[i] & 0xFFFF;
|
|
debug("BAR%d %#lx size: %d",
|
|
i, BAR[i], BARsSize[i]);
|
|
}
|
|
}
|
|
|
|
Memory::Virtual vmm(KernelPageTable);
|
|
|
|
/* Mapping the BARs */
|
|
for (short i = 0; i < 6; i++)
|
|
{
|
|
if (BAR[i] == 0)
|
|
continue;
|
|
|
|
if ((BAR[i] & 1) == 0) /* Memory Base */
|
|
{
|
|
uintptr_t BARBase = BAR[i] & (~15);
|
|
size_t BARSize = BARsSize[i];
|
|
|
|
debug("Mapping BAR%d %#lx-%#lx",
|
|
i, BARBase, BARBase + BARSize);
|
|
|
|
if (BARSize == 0)
|
|
{
|
|
warn("BAR%d size is zero!", i);
|
|
BARSize++;
|
|
}
|
|
|
|
vmm.Map((void *)BARBase, (void *)BARBase,
|
|
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
|
}
|
|
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
|
{
|
|
uintptr_t BARBase = BAR[i] & (~3);
|
|
size_t BARSize = BARsSize[i];
|
|
|
|
debug("Mapping BAR%d %#x-%#x",
|
|
i, BARBase, BARBase + BARSize);
|
|
|
|
if (BARSize == 0)
|
|
{
|
|
warn("BAR%d size is zero!", i);
|
|
BARSize++;
|
|
}
|
|
|
|
vmm.Map((void *)BARBase, (void *)BARBase,
|
|
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 1: /* PCI Header 1 (PCI-to-PCI Bridge) */
|
|
{
|
|
fixme("PCI Header 1 (PCI-to-PCI Bridge) not implemented yet");
|
|
break;
|
|
}
|
|
case 2: /* PCI Header 2 (PCI-to-CardBus Bridge) */
|
|
{
|
|
fixme("PCI Header 2 (PCI-to-CardBus Bridge) not implemented yet");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
error("Unknown header type %d", Header->HeaderType);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Header->Command |= PCI_COMMAND_MASTER |
|
|
PCI_COMMAND_IO |
|
|
PCI_COMMAND_MEMORY;
|
|
Header->Command &= ~PCI_COMMAND_INTX_DISABLE;
|
|
}
|
|
|
|
uint32_t GetBAR(dev_t MajorID, uint8_t i, void *_Header)
|
|
{
|
|
dbg_api("%d, %d, %#lx", MajorID, i, _Header);
|
|
|
|
PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header;
|
|
|
|
switch (Header->HeaderType)
|
|
{
|
|
case 128:
|
|
warn("Unknown header type %d! Guessing PCI Header 0",
|
|
Header->HeaderType);
|
|
[[fallthrough]];
|
|
case 0: /* PCI Header 0 */
|
|
{
|
|
PCI::PCIHeader0 *hdr0 =
|
|
(PCI::PCIHeader0 *)Header;
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
return hdr0->BAR0;
|
|
case 1:
|
|
return hdr0->BAR1;
|
|
case 2:
|
|
return hdr0->BAR2;
|
|
case 3:
|
|
return hdr0->BAR3;
|
|
case 4:
|
|
return hdr0->BAR4;
|
|
case 5:
|
|
return hdr0->BAR5;
|
|
default:
|
|
assert(!"Invalid BAR index");
|
|
}
|
|
}
|
|
case 1: /* PCI Header 1 (PCI-to-PCI Bridge) */
|
|
{
|
|
PCI::PCIHeader1 *hdr1 =
|
|
(PCI::PCIHeader1 *)Header;
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
return hdr1->BAR0;
|
|
case 1:
|
|
return hdr1->BAR1;
|
|
default:
|
|
assert(!"Invalid BAR index");
|
|
}
|
|
}
|
|
case 2: /* PCI Header 2 (PCI-to-CardBus Bridge) */
|
|
{
|
|
assert(!"PCI-to-CardBus Bridge not supported");
|
|
}
|
|
default:
|
|
assert(!"Invalid PCI header type");
|
|
}
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
void *api__memcpy(dev_t MajorID, void *Destination, const void *Source, size_t Length)
|
|
{
|
|
dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length);
|
|
|
|
return memcpy(Destination, Source, Length);
|
|
}
|
|
|
|
void *api__memset(dev_t MajorID, void *Destination, int Value, size_t Length)
|
|
{
|
|
dbg_api("%d, %#lx, %d, %d", MajorID, Destination, Value, Length);
|
|
|
|
return memset(Destination, Value, Length);
|
|
}
|
|
|
|
void *api__memmove(dev_t MajorID, void *Destination, const void *Source, size_t Length)
|
|
{
|
|
dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length);
|
|
|
|
return memmove(Destination, Source, Length);
|
|
}
|
|
|
|
int api__memcmp(dev_t MajorID, const void *Left, const void *Right, size_t Length)
|
|
{
|
|
dbg_api("%d, %#lx, %#lx, %d", MajorID, Left, Right, Length);
|
|
|
|
return memcmp(Left, Right, Length);
|
|
}
|
|
|
|
size_t api__strlen(dev_t MajorID, const char *String)
|
|
{
|
|
dbg_api("%d, %s", MajorID, String);
|
|
|
|
return strlen(String);
|
|
}
|
|
|
|
char *api__strcpy(dev_t MajorID, char *Destination, const char *Source)
|
|
{
|
|
dbg_api("%d, %#lx, %s", MajorID, Destination, Source);
|
|
|
|
return strcpy(Destination, Source);
|
|
}
|
|
|
|
char *api__strcat(dev_t MajorID, char *Destination, const char *Source)
|
|
{
|
|
dbg_api("%d, %#lx, %s", MajorID, Destination, Source);
|
|
|
|
return strcat(Destination, Source);
|
|
}
|
|
|
|
int api__strcmp(dev_t MajorID, const char *Left, const char *Right)
|
|
{
|
|
dbg_api("%d, %s, %s", MajorID, Left, Right);
|
|
|
|
return strcmp(Left, Right);
|
|
}
|
|
|
|
int api__strncmp(dev_t MajorID, const char *Left, const char *Right, size_t Length)
|
|
{
|
|
dbg_api("%d, %s, %s, %d", MajorID, Left, Right, Length);
|
|
|
|
return strncmp(Left, Right, Length);
|
|
}
|
|
|
|
char *api__strchr(dev_t MajorID, const char *String, int Character)
|
|
{
|
|
dbg_api("%d, %s, %d", MajorID, String, Character);
|
|
|
|
return strchr(String, Character);
|
|
}
|
|
|
|
char *api__strrchr(dev_t MajorID, const char *String, int Character)
|
|
{
|
|
dbg_api("%d, %s, %d", MajorID, String, Character);
|
|
|
|
stub;
|
|
return nullptr;
|
|
// return strrchr(String, Character);
|
|
}
|
|
|
|
char *api__strstr(dev_t MajorID, const char *Haystack, const char *Needle)
|
|
{
|
|
dbg_api("%d, %s, %s", MajorID, Haystack, Needle);
|
|
|
|
return strstr(Haystack, Needle);
|
|
}
|
|
|
|
/* --------- */
|
|
|
|
void PopulateDriverAPI(void *API)
|
|
{
|
|
__driverAPI *api = (__driverAPI *)API;
|
|
|
|
api->RegisterFunction = RegisterFunction;
|
|
api->GetDriverInfo = GetDriverInfo;
|
|
|
|
api->RegisterInterruptHandler = RegisterInterruptHandler;
|
|
api->OverrideInterruptHandler = OverrideInterruptHandler;
|
|
api->UnregisterInterruptHandler = UnregisterInterruptHandler;
|
|
api->UnregisterAllInterruptHandlers = UnregisterAllInterruptHandlers;
|
|
|
|
api->RegisterInputDevice = RegisterInputDevice;
|
|
api->UnregisterInputDevice = UnregisterInputDevice;
|
|
api->ReportKeyboardEvent = ReportKeyboardEvent;
|
|
api->ReportRelativeMouseEvent = ReportRelativeMouseEvent;
|
|
api->ReportAbsoluteMouseEvent = ReportAbsoluteMouseEvent;
|
|
|
|
api->RegisterBlockDevice = RegisterBlockDevice;
|
|
api->UnregisterBlockDevice = UnregisterBlockDevice;
|
|
|
|
api->RegisterAudioDevice = RegisterAudioDevice;
|
|
api->UnregisterAudioDevice = UnregisterAudioDevice;
|
|
|
|
api->RegisterNetDevice = RegisterNetDevice;
|
|
api->UnregisterNetDevice = UnregisterNetDevice;
|
|
api->ReportNetworkPacket = ReportNetworkPacket;
|
|
|
|
api->KPrint = d_KPrint;
|
|
api->KernelLog = KernelLog;
|
|
|
|
api->RequestPages = RequestPages;
|
|
api->FreePages = FreePages;
|
|
|
|
api->AppendMapFlag = AppendMapFlag;
|
|
api->RemoveMapFlag = RemoveMapFlag;
|
|
api->MapPages = MapPages;
|
|
api->UnmapPages = UnmapPages;
|
|
|
|
api->CreateKernelProcess = CreateKernelProcess;
|
|
api->CreateKernelThread = CreateKernelThread;
|
|
api->KillProcess = KillProcess;
|
|
api->KillThread = KillThread;
|
|
api->Yield = Yield;
|
|
api->Sleep = Sleep;
|
|
|
|
api->GetPCIDevices = GetPCIDevices;
|
|
api->InitializePCI = InitializePCI;
|
|
api->GetBAR = GetBAR;
|
|
|
|
api->memcpy = api__memcpy;
|
|
api->memset = api__memset;
|
|
api->memmove = api__memmove;
|
|
api->memcmp = api__memcmp;
|
|
api->strlen = api__strlen;
|
|
api->strcpy = api__strcpy;
|
|
api->strcat = api__strcat;
|
|
api->strcmp = api__strcmp;
|
|
api->strncmp = api__strncmp;
|
|
api->strchr = api__strchr;
|
|
api->strrchr = api__strrchr;
|
|
api->strstr = api__strstr;
|
|
}
|
|
}
|