mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-07-01 18:39:16 +00:00
fix(kernel/vfs): 🎉 a complete rewrite of the vfs
This is the fourth time re-writing the VFS, hope this will be the last. Tried to make it as modular as possible so this won't be necessary in the future. 🙏
This change required the entire kernel code to be modified.
This commit is contained in:
91
Kernel/drivers/fs/ext2/ext2.hpp
Normal file
91
Kernel/drivers/fs/ext2/ext2.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
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_FILESYSTEM_EXT2_H__
|
||||
#define __FENNIX_KERNEL_FILESYSTEM_EXT2_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
namespace Driver::ExtendedFilesystem
|
||||
{
|
||||
class EXT2
|
||||
{
|
||||
public:
|
||||
struct SuperBlock
|
||||
{
|
||||
uint32_t Inodes;
|
||||
uint32_t Blocks;
|
||||
uint32_t ReservedBlocks;
|
||||
uint32_t FreeBlock;
|
||||
uint32_t FreeInodes;
|
||||
uint32_t FirstDataBlock;
|
||||
uint32_t LogBlockSize;
|
||||
uint32_t LogFragSize;
|
||||
uint32_t BlocksPerGroup;
|
||||
uint32_t FragsPerGroup;
|
||||
uint32_t InodesPerGroup;
|
||||
uint32_t LastMountTime;
|
||||
uint32_t LastWrittenTime;
|
||||
uint16_t MountedTimes;
|
||||
uint16_t MaximumMountedTimes;
|
||||
uint16_t Magic;
|
||||
uint16_t State;
|
||||
uint16_t Errors;
|
||||
uint16_t MinorRevLevel;
|
||||
uint32_t LastCheck;
|
||||
uint32_t CheckInternval;
|
||||
uint32_t SystemID;
|
||||
uint32_t RevLevel;
|
||||
uint16_t ReservedBlocksUserID;
|
||||
uint16_t ReservedBlocksGroupID;
|
||||
|
||||
uint32_t FirstInode;
|
||||
uint16_t InodeSize;
|
||||
uint16_t BlockGroups;
|
||||
uint32_t FeatureCompatibility;
|
||||
uint32_t FeatureIncompatibility;
|
||||
uint32_t FeatureRoCompatibility;
|
||||
uint8_t UUID[16];
|
||||
char VolumeName[16];
|
||||
char LastMounted[64];
|
||||
uint32_t BitmapAlogrithm;
|
||||
|
||||
uint8_t PreallocatedBlocks;
|
||||
uint8_t PreallocatedDirectoryBlocks;
|
||||
|
||||
uint16_t Padding;
|
||||
uint8_t JournalUUID[16];
|
||||
uint32_t JournalInum;
|
||||
uint32_t JournalDev;
|
||||
uint32_t LastOrphan;
|
||||
uint32_t HashSeed[4];
|
||||
uint8_t DefHashVersion;
|
||||
uint8_t ReservedCharPad;
|
||||
uint16_t ReservedWordPad;
|
||||
uint32_t DefaultMountOptions;
|
||||
uint32_t FirstMetaBg;
|
||||
uint32_t Reserved[190];
|
||||
};
|
||||
|
||||
EXT2(void *partition);
|
||||
~EXT2();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_FILESYSTEM_EXT2_H__
|
200
Kernel/drivers/fs/ustar/ustar.cpp
Normal file
200
Kernel/drivers/fs/ustar/ustar.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <fs/ustar.hpp>
|
||||
#include <interface/fs.h>
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver::UnixStandardTAR
|
||||
{
|
||||
dev_t DriverID;
|
||||
|
||||
int USTAR_AllocateInode(FileSystemInfo *Info, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_DeleteInode(FileSystemInfo *Info, Inode *Node)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Synchronize(FileSystemInfo *Info, Inode *Node)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Destroy(FileSystemInfo *Info)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Probe(void *Device)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Mount(FileSystemInfo *FS, Inode **Root, void *Device)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Unmount(FileSystemInfo *FS)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Lookup(Inode *Parent, const char *Name, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Create(Inode *Parent, const char *Name, mode_t Mode, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Remove(Inode *Parent, const char *Name)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Rename(Inode *Parent, const char *OldName, const char *NewName)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_Read(Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_Write(Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Truncate(Inode *Node, off_t Size)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Open(Inode *Node, int Flags, mode_t Mode)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Close(Inode *Node)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Ioctl(Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_ReadDir(Inode *Node, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_MkDir(Inode *Parent, const char *Name, mode_t Mode, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_RmDir(Inode *Parent, const char *Name)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_ReadLink(Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
off_t USTAR_Seek(Inode *Node, off_t Offset)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Stat(Inode *Node, kstat *Stat)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
static SuperBlockOperations ustarSuperOps = {
|
||||
.AllocateInode = USTAR_AllocateInode,
|
||||
.DeleteInode = USTAR_DeleteInode,
|
||||
.Synchronize = USTAR_Synchronize,
|
||||
.Destroy = USTAR_Destroy,
|
||||
.Probe = USTAR_Probe,
|
||||
.Mount = USTAR_Mount,
|
||||
.Unmount = USTAR_Unmount};
|
||||
|
||||
static InodeOperations ustarInodeOps = {
|
||||
.Lookup = USTAR_Lookup,
|
||||
.Create = USTAR_Create,
|
||||
.Remove = USTAR_Remove,
|
||||
.Rename = USTAR_Rename,
|
||||
.Read = USTAR_Read,
|
||||
.Write = USTAR_Write,
|
||||
.Truncate = USTAR_Truncate,
|
||||
.Open = USTAR_Open,
|
||||
.Close = USTAR_Close,
|
||||
.Ioctl = USTAR_Ioctl,
|
||||
.ReadDir = USTAR_ReadDir,
|
||||
.MkDir = USTAR_MkDir,
|
||||
.RmDir = USTAR_RmDir,
|
||||
.SymLink = USTAR_SymLink,
|
||||
.ReadLink = USTAR_ReadLink,
|
||||
.Seek = USTAR_Seek,
|
||||
.Stat = USTAR_Stat};
|
||||
|
||||
int Entry()
|
||||
{
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Unix Standard TAR";
|
||||
fsi->SuperOps = ustarSuperOps;
|
||||
fsi->Ops = ustarInodeOps;
|
||||
v0::RegisterFileSystem(DriverID, fsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Final() { return 0; }
|
||||
int Panic() { return 0; }
|
||||
int Probe() { return 0; }
|
||||
|
||||
REGISTER_BUILTIN_DRIVER(ustar,
|
||||
"Unix Standard TAR Driver",
|
||||
"enderice2",
|
||||
1, 0, 0,
|
||||
Entry,
|
||||
Final,
|
||||
Panic,
|
||||
Probe);
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <interface/block.h>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
|
||||
@ -572,6 +573,9 @@ namespace Driver::AHCI
|
||||
HBAPort *HBAPortPtr;
|
||||
uint8_t *Buffer;
|
||||
uint8_t PortNumber;
|
||||
uint32_t BlockSize;
|
||||
uint32_t BlockCount;
|
||||
size_t Size;
|
||||
ATA_IDENTIFY *IdentifyData;
|
||||
|
||||
Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
|
||||
@ -614,6 +618,7 @@ namespace Driver::AHCI
|
||||
|
||||
void Configure()
|
||||
{
|
||||
debug("Configuring port %d", PortNumber);
|
||||
this->StopCMD();
|
||||
void *CmdBase = v0::AllocateMemory(DriverID, 1);
|
||||
HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
|
||||
@ -639,19 +644,35 @@ namespace Driver::AHCI
|
||||
|
||||
Identify();
|
||||
|
||||
if (IdentifyData->CommandSetSupport.BigLba)
|
||||
{
|
||||
if ((IdentifyData->CommandSetActive.Words119_120Valid & 0x1) != 0)
|
||||
{
|
||||
uint32_t wordsPerLogicalSector = (IdentifyData->WordsPerLogicalSector[1] << 16) | IdentifyData->WordsPerLogicalSector[0];
|
||||
if (wordsPerLogicalSector != 0)
|
||||
this->BlockSize = wordsPerLogicalSector * 2;
|
||||
}
|
||||
}
|
||||
this->BlockSize = 512;
|
||||
|
||||
this->BlockCount = this->IdentifyData->UserAddressableSectors;
|
||||
this->Size = this->BlockCount * this->BlockSize;
|
||||
|
||||
trace("Port %d \"%x %x %x %x\" configured", PortNumber,
|
||||
HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
|
||||
HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]);
|
||||
}
|
||||
|
||||
bool ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
|
||||
int ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
|
||||
{
|
||||
if (this->AHCIPortType == PortType::SATAPI && Write == true)
|
||||
{
|
||||
trace("SATAPI port does not support write.");
|
||||
return false;
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
debug("%s op on port %d, sector %d, count %d", Write ? "Write" : "Read", this->PortNumber, Sector, SectorCount);
|
||||
|
||||
uint32_t SectorL = (uint32_t)Sector;
|
||||
uint32_t SectorH = (uint32_t)(Sector >> 32);
|
||||
|
||||
@ -706,7 +727,7 @@ namespace Driver::AHCI
|
||||
if (spinLock == 1000000)
|
||||
{
|
||||
trace("Port not responding.");
|
||||
return false;
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
HBAPortPtr->CommandIssue = 1;
|
||||
@ -723,7 +744,7 @@ namespace Driver::AHCI
|
||||
spinLock = 0;
|
||||
retries++;
|
||||
if (retries > 10)
|
||||
return false;
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (HBAPortPtr->CommandIssue == 0)
|
||||
@ -733,11 +754,11 @@ namespace Driver::AHCI
|
||||
if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
|
||||
{
|
||||
trace("Error reading/writing (%d).", Write);
|
||||
return false;
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Identify()
|
||||
@ -840,34 +861,61 @@ namespace Driver::AHCI
|
||||
}
|
||||
}
|
||||
|
||||
int Open(struct Inode *, int, mode_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Close(struct Inode *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
uint64_t sector = Offset / 512;
|
||||
uint32_t sectorCount = uint32_t(Size / 512);
|
||||
int num = Node->GetMinor();
|
||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, Buffer, false);
|
||||
return ok ? Size : 0;
|
||||
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||
{
|
||||
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint64_t sector = Offset / port->BlockSize;
|
||||
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
|
||||
if (sectorCount == 0)
|
||||
{
|
||||
trace("Attempt to read 0 sectors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool status = port->ReadWrite(sector, sectorCount, Buffer, false);
|
||||
if (status != 0)
|
||||
{
|
||||
trace("Error '%s' reading from port %d", strerror(status), port->PortNumber);
|
||||
return status;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
uint64_t sector = Offset / 512;
|
||||
uint32_t sectorCount = uint32_t(Size / 512);
|
||||
int num = Node->GetMinor();
|
||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, (void *)Buffer, true);
|
||||
return ok ? Size : 0;
|
||||
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||
{
|
||||
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint64_t sector = Offset / port->BlockSize;
|
||||
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
|
||||
if (sectorCount == 0)
|
||||
{
|
||||
trace("Attempt to write 0 sectors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool status = port->ReadWrite(sector, sectorCount, (void *)Buffer, true);
|
||||
if (status != 0)
|
||||
{
|
||||
trace("Error '%s' writing to port %d", strerror(status), port->PortNumber);
|
||||
return status;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
int Open(struct Inode *, int, mode_t) { return 0; }
|
||||
int Close(struct Inode *) { return 0; }
|
||||
|
||||
const struct InodeOperations ops = {
|
||||
.Lookup = nullptr,
|
||||
.Create = nullptr,
|
||||
@ -915,8 +963,18 @@ namespace Driver::AHCI
|
||||
{
|
||||
KPrint("%s drive found at port %d", PortTypeName[portType], i);
|
||||
Port *port = new Port(portType, &hba->Ports[i], i);
|
||||
dev_t ret = v0::RegisterDevice(DriverID, BLOCK_TYPE_HDD, &ops);
|
||||
port->Configure();
|
||||
|
||||
BlockDevice *dev = new BlockDevice;
|
||||
dev->Name = "ahci";
|
||||
dev->BlockSize = port->BlockSize;
|
||||
dev->BlockCount = port->BlockCount;
|
||||
dev->Size = port->Size;
|
||||
dev->Ops = &ops;
|
||||
dev->PrivateData = port;
|
||||
dev_t ret = v0::RegisterBlockDevice(DriverID, dev);
|
||||
PortDevices[ret] = port;
|
||||
debug("Port %d \"%s\" registered as %d", i, port->IdentifyData->ModelNumber, ret);
|
||||
break;
|
||||
}
|
||||
case PortType::SEMB:
|
||||
@ -942,10 +1000,6 @@ namespace Driver::AHCI
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
trace("Initializing AHCI ports");
|
||||
for (auto &&p : PortDevices)
|
||||
p.second->Configure();
|
||||
|
||||
/* We don't use the interrupt handler now... maybe we will in the future */
|
||||
// RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
|
||||
|
||||
@ -957,7 +1011,7 @@ namespace Driver::AHCI
|
||||
for (auto &&p : PortDevices)
|
||||
{
|
||||
p.second->StopCMD();
|
||||
v0::UnregisterDevice(DriverID, p.first);
|
||||
v0::UnregisterBlockDevice(DriverID, p.first);
|
||||
delete p.second;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user