diff options
Diffstat (limited to 'Source/Kernel')
36 files changed, 969 insertions, 97 deletions
diff --git a/Source/Kernel/Core/Log.ns.cpp b/Source/Kernel/Core/Log.ns.cpp index 1727024..c8ccd80 100644 --- a/Source/Kernel/Core/Log.ns.cpp +++ b/Source/Kernel/Core/Log.ns.cpp @@ -1,4 +1,5 @@ #include "Log.ns.h" +#include <FileSystems/RamFS/RamFS.class.h> #include <VFS/VFS.ns.h> namespace Log { @@ -11,6 +12,10 @@ void init(u8int loglevel) { if (VFS::find("/System/Logs") == 0) VFS::createDirectory("/System/Logs"); logs[KL_PANIC] = new TextFile("/System/Logs/Panic.log", FM_APPEND); + if (!logs[KL_PANIC]->valid()) { //FS maybee not read/write, mount a ramfs + RamFS::mount(1024*1024, (DirectoryNode*)VFS::find("/System/Logs")); + logs[KL_PANIC] = new TextFile("/System/Logs/Panic.log", FM_APPEND); + } if (KL_CRITICAL <= loglevel) logs[KL_CRITICAL] = new TextFile("/System/Logs/Critical.log", FM_APPEND); if (KL_ERROR <= loglevel) logs[KL_ERROR] = new TextFile("/System/Logs/Error.log", FM_APPEND); if (KL_WARNING <= loglevel) logs[KL_WARNING] = new TextFile("/System/Logs/Warning.log", FM_APPEND); diff --git a/Source/Kernel/Core/Sys.ns.cpp b/Source/Kernel/Core/Sys.ns.cpp index eeb92ee..49b2725 100644 --- a/Source/Kernel/Core/Sys.ns.cpp +++ b/Source/Kernel/Core/Sys.ns.cpp @@ -83,7 +83,7 @@ void dumpRegs(registers_t *regs, VirtualTerminal& vt) { void stackTrace(u32int ebp, VirtualTerminal& vt, u32int maxframes) { u32int *stack = (u32int*)ebp; - for (u32int i = 0; i < maxframes and (u32int)stack > 0xC0000000; i++) { + for (u32int i = 0; i < maxframes and (u32int)stack > 0xC0000000 and (u32int)stack < (ebp + 0x10000); i++) { vt << "Frame: " << (u32int)stack << " n:" << stack[0] << " r:" << stack[1] << "\n"; stack = (u32int*)stack[0]; } diff --git a/Source/Kernel/Core/Sys.ns.h b/Source/Kernel/Core/Sys.ns.h index 4d15676..9b34dbf 100644 --- a/Source/Kernel/Core/Sys.ns.h +++ b/Source/Kernel/Core/Sys.ns.h @@ -18,9 +18,12 @@ //This file contains system-relative functions class String; +class SimpleVT; class VirtualTerminal; struct registers_t; +extern SimpleVT* kvt; + namespace Sys { void outb(u16int port, u8int value); u8int inb(u16int port); diff --git a/Source/Kernel/Core/kmain.wtf.cpp b/Source/Kernel/Core/kmain.wtf.cpp index 0486702..a028457 100644 --- a/Source/Kernel/Core/kmain.wtf.cpp +++ b/Source/Kernel/Core/kmain.wtf.cpp @@ -25,6 +25,7 @@ #include <Rand.ns.h> #include <VFS/Part.ns.h> #include <FileSystems/RamFS/RamFS.class.h> +#include <FileSystems/FAT/FATFS.class.h> #include <VFS/FileNode.class.h> #include <VFS/VFS.ns.h> #include <VFS/DirectoryNode.class.h> @@ -37,6 +38,8 @@ extern u32int end; //Placement address extern "C" void kmain(multiboot_info_t* mbd, u32int magic); +SimpleVT* kvt; + u32int logoAnimation(void* p) { SimpleVT& vt = *((SimpleVT*)p); vt.setColor(8); @@ -83,7 +86,7 @@ u32int logoAnimation(void* p) { void selectVideoMode(SimpleVT& v) { Disp::getModes(); - v << "\n\nPlease select a graphic mode in the list below:\n"; + v << "\nPlease select a graphic mode in the list below:\n"; for (u32int i = 0; i < Disp::modes.size(); i++) { Disp::mode_t& m = Disp::modes[i]; @@ -140,9 +143,9 @@ void kmain(multiboot_info_t* mbd, u32int magic) { Disp::setText(vgaout); //Create a VT for logging what kernel does - SimpleVT *kvt = new ScrollableVT(25, 80, 20, KVT_FGCOLOR, KVT_BGCOLOR); + kvt = new ScrollableVT(25, 80, 20, KVT_FGCOLOR, KVT_BGCOLOR); kvt->map(0, 0); - *kvt << "Melon is loading..."; + *kvt << "Melon is loading...\n"; IDT::init(); //Setup interrupts @@ -164,13 +167,17 @@ void kmain(multiboot_info_t* mbd, u32int magic) { //*************************************** PARSE COMMAND LINE Vector<String> opts = kcmdline.split(" "); - String keymap = "fr", init = "/System/Applications/PaperWork.app"; + String keymap = "builtin", init = "/System/Applications/PaperWork.app"; + String root = "ramfs:0"; + Vector<String> mount; bool enableVESA = true; for (u32int i = 0; i < opts.size(); i++) { Vector<String> opt = opts[i].split(":"); if (opt[0] == "vesa" && opt[1] != "enabled") enableVESA = false; if (opt[0] == "keymap") keymap = opt[1]; if (opt[0] == "init") init = opt[1]; + if (opt[0] == "root") root = opts[i].substr(5); + if (opt[0] == "mount") mount.push(opts[i].substr(6)); } //*************************************** DEVICE SETUP @@ -180,16 +187,26 @@ void kmain(multiboot_info_t* mbd, u32int magic) { if (enableVESA) Dev::registerDevice(new VESADisplay()); FloppyController::detect(); - //*************************************** MOUNT ROOT FILESYSTEM + //*************************************** MOUNT FILESYSTEMS - FileSystem* fs = RamFS::mount((u8int*)mods[0].mod_start, 1024 * 1024, NULL); + { // mount root filesystem + if (!VFS::mount(String("/:") += root, kvt, mbd)) PANIC("Cannot mount root filesystem."); + } DirectoryNode* cwd; - cwd = fs->getRootNode(); + cwd = VFS::getRootNode(); Task::currProcess()->setCwd(cwd); - VFS::setRootNode(cwd); + + // mount other filesystems + for (u32int i = 0; i < mount.size(); i++) { + VFS::mount(mount[i], kvt, mbd); + } + + //FATFS::mount(Part::partitions[0], (DirectoryNode*)VFS::createDirectory("/Mount")); + + //*************************************** LOAD SYSTEM STUFF if (keymap != "builtin") { - if (!Kbd::loadKeymap(keymap)) *kvt << "\nWARNING : Could not load keymap " << keymap << ", using built-in keymap instead."; + if (!Kbd::loadKeymap(keymap)) *kvt << "WARNING : Could not load keymap " << keymap << ", using built-in keymap instead."; } Log::init(KL_STATUS); //Setup logging @@ -199,7 +216,7 @@ void kmain(multiboot_info_t* mbd, u32int magic) { Log::log(KL_STATUS, "kmain : User list loaded"); if (init.empty()) { - *kvt << "\n\n"; + *kvt << "\n"; new KernelShell(cwd, kvt); while (KernelShell::getInstances() > 0) { Task::currThread()->sleep(100); diff --git a/Source/Kernel/Devices/Floppy/FloppyController.class.cpp b/Source/Kernel/Devices/Floppy/FloppyController.class.cpp index 146ce28..7201c5c 100644 --- a/Source/Kernel/Devices/Floppy/FloppyController.class.cpp +++ b/Source/Kernel/Devices/Floppy/FloppyController.class.cpp @@ -96,6 +96,7 @@ FloppyController::FloppyController(u32int base, u8int irq) : m_driveMutex(false) m_drives[0] = NULL; m_drives[1] = NULL; m_first = false; + Dev::requestIRQ(this, m_irq); } void FloppyController::detect() { //TODO : do this better @@ -144,16 +145,14 @@ void FloppyController::setDOR() { dor |= 0x10; if (m_drives[1] != NULL and m_drives[1]->m_motorState != 0) dor |= 0x20; - asm volatile ("cli"); + resetIrq(); outb(m_base + FR_DOR, dor); if (m_first) { //First time we set the DOR, controller initialized - Task::currThread()->waitIRQ(m_irq); + waitIrq(); int st0, cyl; checkInterrupt(&st0, &cyl); m_first = false; } - asm volatile ("sti"); - //PANIC("test"); } void FloppyController::setActiveDrive(u8int drive) { @@ -190,10 +189,10 @@ u8int FloppyController::readData() { bool FloppyController::reset() { outb(m_base + FR_DOR, 0x00); //Disable controller m_first = true; - setNoActiveDrive(); if (m_drives[0] != NULL) m_drives[0]->m_motorState = 0; if (m_drives[1] != NULL) m_drives[1]->m_motorState = 0; + setNoActiveDrive(); for (int i = 0; i < 2; i++) { if (m_drives[i] != NULL) { @@ -203,3 +202,11 @@ bool FloppyController::reset() { } return true; } + +void FloppyController::handleIRQ(registers_t regs, int irq) { + m_irqHappened = true; +} + +void FloppyController::waitIrq() { + while (!m_irqHappened) Task::currThread()->sleep(10); +} diff --git a/Source/Kernel/Devices/Floppy/FloppyController.class.h b/Source/Kernel/Devices/Floppy/FloppyController.class.h index a27d853..f0a7c10 100644 --- a/Source/Kernel/Devices/Floppy/FloppyController.class.h +++ b/Source/Kernel/Devices/Floppy/FloppyController.class.h @@ -60,6 +60,8 @@ class FloppyController : public Device { bool m_first; + bool m_irqHappened; + FloppyDrive* m_drives[2]; void checkInterrupt(int *st0, int *cyl); @@ -69,6 +71,10 @@ class FloppyController : public Device { bool writeCmd(u8int cmd); //Sends command to controller u8int readData(); //Reads a byte from controller bool reset(); + + void handleIRQ(registers_t regs, int irq); + void resetIrq() { m_irqHappened = false; } + void waitIrq(); public: static void detect(); diff --git a/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp b/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp index 7edf24a..b7fd69b 100644 --- a/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp +++ b/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp @@ -2,6 +2,7 @@ #include "FloppyController.class.h" #include <TaskManager/Task.ns.h> #include <DeviceManager/Time.ns.h> +#include <VTManager/SimpleVT.class.h> #include <Core/Log.ns.h> using namespace Sys; @@ -91,16 +92,18 @@ bool FloppyDrive::calibrate() { int st0, cyl = -1; - if (!setMotorState(true)) return false; + if (!setMotorState(true)) { + *kvt << getName() << ": calibrate fail\n"; + return false; + } for (int i = 0; i < 10; i++) { - asm volatile("cli"); + m_fdc->resetIrq(); m_fdc->writeCmd(FC_RECALIBRATE); m_fdc->writeCmd(m_driveNumber); - Task::currThread()->waitIRQ(m_fdc->m_irq); + m_fdc->waitIrq(); m_fdc->checkInterrupt(&st0, &cyl); - asm volatile("sti"); if (st0 & 0xC0) { continue; @@ -111,6 +114,7 @@ bool FloppyDrive::calibrate() { } } setMotorState(false); + *kvt << getName() << ": calibrate fail\n"; return false; } @@ -137,47 +141,44 @@ bool FloppyDrive::killMotor() { return true; } -bool FloppyDrive::seek(u32int cyli, s32int head) { +bool FloppyDrive::seek(u32int cyli, s32int head, bool recursive) { if (cyli >= m_cylinders) return false; - m_fdc->setActiveDrive(m_driveNumber); setMotorState(true); //Turn on motor int st0, cyl = -1; - for (u32int i = 0; i < 10; i++) { - asm volatile ("cli"); + for (u32int i = 0; i < (recursive ? 10 : 5); i++) { + m_fdc->resetIrq(); m_fdc->writeCmd(FC_SEEK); - m_fdc->writeCmd(head << 2); + m_fdc->writeCmd(head << 2 | m_driveNumber); m_fdc->writeCmd(cyl); - Task::currThread()->waitIRQ(m_fdc->m_irq); + m_fdc->waitIrq(); m_fdc->checkInterrupt(&st0, &cyl); - asm volatile("sti"); if (st0 & 0xC0) { //Error continue; } - if (cyl == 0xFF or cyl == 0x00) { //0xFF for bochs, 0x00 for qemu :D - setMotorState(false); - m_fdc->setNoActiveDrive(); - return true; - } - if (cyl == (int)cyli) { + if (cyl == 0xFF or cyl == 0x00 or cyl == (int)cyli) { //0xFF for bochs, 0x00 for qemu :D setMotorState(false); - m_fdc->setNoActiveDrive(); return true; } } - setMotorState(false); - m_fdc->setNoActiveDrive(); - return false; + if (recursive) { + setMotorState(false); + *kvt << getName() << ": seek fail\n"; + return false; + } else { + calibrate(); + return seek(cyli, head, true); + } } bool FloppyDrive::doTrack(u32int cyl, u8int dir) { + m_fdc->setActiveDrive(m_driveNumber); if (!seek(cyl, 0)) return false; if (!seek(cyl, 1)) return false; - m_fdc->setActiveDrive(m_driveNumber); u8int cmd, flags = 0xC0; switch (dir) { @@ -203,7 +204,7 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) { Task::currThread()->sleep(100); - asm volatile("cli"); + m_fdc->resetIrq(); m_fdc->writeCmd(cmd); m_fdc->writeCmd(m_driveNumber); //Drive number & first head << 2 m_fdc->writeCmd(cyl); //Cylinder @@ -214,7 +215,7 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) { m_fdc->writeCmd(0x1B); m_fdc->writeCmd(0xFF); - Task::currThread()->waitIRQ(m_fdc->m_irq); + m_fdc->waitIrq(); u8int st0, st1, st2, rcy, rhe, rse, bps; st0 = m_fdc->readData(); @@ -224,7 +225,6 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) { rhe = m_fdc->readData(); rse = m_fdc->readData(); bps = m_fdc->readData(); - asm volatile("sti"); int error = 0; @@ -274,12 +274,11 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) { bool FloppyDrive::readOnly() { m_fdc->setActiveDrive(m_driveNumber); - asm volatile("cli"); + m_fdc->resetIrq(); m_fdc->writeCmd(FC_SENSE_DRIVE_STATUS); m_fdc->writeCmd(m_driveNumber); - Task::currThread()->waitIRQ(m_fdc->m_irq); + m_fdc->waitIrq(); u8int st3 = m_fdc->readData(); - asm volatile("sti"); bool ret = (st3 & 0x80 ? true : false); @@ -296,16 +295,13 @@ bool FloppyDrive::readBlocks(u64int start, u32int count, u8int *data) { u32int startblock = start; if (count == 1) { u32int cylinder = (startblock / (m_sectors * 2)), offset = (startblock % (m_sectors * 2)) * 512; - if (m_buffCyl == cylinder && m_buffTime >= Time::uptime() - 4) { - memcpy(data, (const u8int*)(&m_buffer[offset]), 512); - return true; - } else { + if (m_buffCyl != cylinder or m_buffTime < Time::uptime() - 4) { if (!doTrack(cylinder, FD_READ)) return false; m_buffCyl = cylinder; m_buffTime = Time::uptime(); - memcpy(data, (const u8int*)(&m_buffer[offset]), 512); - return true; } + memcpy(data, (const u8int*)(&m_buffer[offset]), 512); + return true; } else { m_buffCyl = 0xFFFF; //Invalid cylinder m_buffTime = 0; diff --git a/Source/Kernel/Devices/Floppy/FloppyDrive.class.h b/Source/Kernel/Devices/Floppy/FloppyDrive.class.h index 75926ea..73229b1 100644 --- a/Source/Kernel/Devices/Floppy/FloppyDrive.class.h +++ b/Source/Kernel/Devices/Floppy/FloppyDrive.class.h @@ -22,7 +22,7 @@ class FloppyDrive : public BlockDevice { bool calibrate(); bool setMotorState(bool on); bool killMotor(); - bool seek(u32int cyli, s32int head); + bool seek(u32int cyli, s32int head, bool recursive = false); bool doTrack(u32int cyl, u8int dir); public: diff --git a/Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h b/Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h new file mode 100644 index 0000000..c2f55e1 --- /dev/null +++ b/Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h @@ -0,0 +1,16 @@ +#ifndef DEF_FATDIRECTORYNODE_CLASS_H +#define DEF_FATDIRECTORYNODE_CLASS_H + +#include <VFS/DirectoryNode.class.h> + +class FATDirectoryNode : public DirectoryNode { + friend class FATFS; + FATDirectoryNode(String name, FileSystem* fs, FSNode* parent, u32int permissions = 0777, + u32int uid = 0, u32int gid = 0) : + DirectoryNode(name, fs, parent, permissions, uid, gid) {} + + u32int m_firstCluster; + u32int m_firstDirEntryID; //id of the first directory entry corresponding to this file in parent directory +}; + +#endif diff --git a/Source/Kernel/FileSystems/FAT/FATFS.class.cpp b/Source/Kernel/FileSystems/FAT/FATFS.class.cpp new file mode 100644 index 0000000..4c20b3f --- /dev/null +++ b/Source/Kernel/FileSystems/FAT/FATFS.class.cpp @@ -0,0 +1,247 @@ +#include "FATFS.class.h" +#include <VTManager/SimpleVT.class.h> +#include "FATFileNode.class.h" +#include "FATDirectoryNode.class.h" +#include <VFS/VFS.ns.h> +#include <ByteArray.class.h> + +#define FIRSTCLUS(node) ((u32int&)(node->type() == NT_DIRECTORY ? \ + ((FATDirectoryNode*)(node))->m_firstCluster : \ + ((FATFileNode*)(node))->m_firstCluster)) +#define FIRSTDEID(node) ((u32int&)(node->type() == NT_DIRECTORY ? \ + ((FATDirectoryNode*)(node))->m_firstDirEntryID : \ + ((FATFileNode*)(node))->m_firstDirEntryID)) + +FileSystem* FATFS::mount(Partition* p, DirectoryNode* mountpoint, bool readwrite) { + if (readwrite) return 0; + if (mountpoint != 0 and !mountpoint->mountpointable()) return 0; + // *** READ BOOT SECTOR *** + union { + fat_BS_t s; + u8int c[512]; + } bs; + if (!p->readBlocks(0, 1, bs.c)) return 0; + // *** CHECK FILESYSTEM TYPE *** + if (bs.s.extBS_16.boot_signature != 0x28 and bs.s.extBS_16.boot_signature != 0x29 + and bs.s.extBS_32.boot_signature != 0x28 and bs.s.extBS_32.boot_signature != 0x29) return 0; + // *** DO SOME CALCULATIONS *** + FATFS* fs = new FATFS(p); + fs->m_fatSize = (bs.s.table_size_16 == 0 ? bs.s.extBS_32.table_size_32 : bs.s.table_size_16); + fs->m_totalSectors = (bs.s.total_sectors_16 == 0 ? bs.s.total_sectors_32 : bs.s.total_sectors_16); + fs->m_rootDirSectors = ((bs.s.root_entry_count * 32) + (bs.s.bytes_per_sector - 1)) / bs.s.bytes_per_sector; + fs->m_firstDataSector = bs.s.reserved_sector_count + (fs->m_fatSize * bs.s.table_count); + fs->m_clusterSize = bs.s.bytes_per_sector * bs.s.sectors_per_cluster; + u32int dataSectors = fs->m_totalSectors - (fs->m_firstDataSector + fs->m_rootDirSectors); + fs->m_countOfClusters = dataSectors / bs.s.sectors_per_cluster; + if (fs->m_countOfClusters < 4085) { //Find out FAT type + fs->m_fatType = 12; + } else if (fs->m_countOfClusters < 65525) { + fs->m_fatType = 16; + } else { + fs->m_fatType = 32; + } + fs->m_readOnly = true; + fs->m_bs = bs.s; + // *** CREATE ROOT DIRECTORY NODE *** + fs->m_rootNode = new FATDirectoryNode("/", fs, mountpoint); + FIRSTCLUS(fs->m_rootNode) = 2; + if (fs->m_fatType == 32) FIRSTCLUS(fs->m_rootNode) = bs.s.extBS_32.root_cluster; + if (!fs->m_rootNode->loadContent()) { + *kvt << "Could not read FAT filesystem root directory.\n"; + delete fs; + return 0; + } + fs->m_fatCache.init(fs->m_fatType == 12 ? 8 : (fs->m_fatType == 16 ? 20 : 40)); + if (mountpoint != 0) mountpoint->mount(fs->m_rootNode); + VFS::registerFilesystem(fs); + *kvt << "Detected a FAT" << (s64int)fs->m_fatType << " filesystem.\n" << + "root_dir_sectors:" << fs->m_rootDirSectors << " fat_size:" << fs->m_fatSize << " total_sectors:" << + fs->m_totalSectors << " data_sectors:" << dataSectors << " count_of_clusters:" << fs->m_countOfClusters << + " sizeof(fat_dir_entry_t):" << sizeof(fat_dir_entry_t) << " first_data_sector:" << fs->m_firstDataSector << + " cluster_size:" << fs->m_clusterSize << "\n"; + return fs; +} + +u32int FATFS::nextCluster(u32int cluster) { + u8int fat_table[m_part->blockSize()]; + u32int val; + if (m_fatType == 12) { + u32int fat_offset = cluster + (cluster / 2); + u32int fat_sector = m_bs.reserved_sector_count + (fat_offset / m_part->blockSize()); + u32int ent_offset = fat_offset % m_part->blockSize(); + m_fatCache.readBlocks(fat_sector, 1, fat_table); + u16int tblval = *(u16int*)&fat_table[ent_offset]; + if (cluster & 1) val = tblval >> 4; + else val = tblval & 0x0FFF; + if (val >= 0xFF7) val = 0; + } else if (m_fatType == 16) { + u32int fat_offset = cluster * 2; + u32int fat_sector = m_bs.reserved_sector_count + (fat_offset / m_part->blockSize()); + u32int ent_offset = fat_offset % m_part->blockSize(); + m_fatCache.readBlocks(fat_sector, 1, fat_table); + u16int tblval = *(u16int*)&fat_table[ent_offset]; + val = tblval; + if (tblval >= 0xFFF7) val = 0; + } else if (m_fatType == 32) { + u32int fat_offset = cluster * 4; + u32int fat_sector = m_bs.reserved_sector_count + (fat_offset / m_part->blockSize()); + u32int ent_offset = fat_offset % m_part->blockSize(); + m_fatCache.readBlocks(fat_sector, 1, fat_table); + val = *(u32int*)&fat_table[ent_offset] & 0x0FFFFFFF; + if (val >= 0x0FFFFFF7) val = 0; + } + return val; +} + +bool FATFS::readCluster(u32int cluster, u8int* data) { + u32int firstSector = ((cluster - 2) * m_bs.sectors_per_cluster) + m_firstDataSector; + if (cluster > 2 and m_fatType != 32) firstSector += m_rootDirSectors; + return m_part->readBlocks(firstSector, m_bs.sectors_per_cluster, data); +} + +bool FATFS::unmount() { + if (m_readOnly) return true; + return false; +} + +bool FATFS::setName(FSNode* node, String name) { + if (m_readOnly) return false; + return false; +} + +bool FATFS::setPermissions(FSNode* node, u32int permissions) { + if (m_readOnly) return false; + return false; +} + +bool FATFS::setUid(FSNode* node, u32int uid) { + if (m_readOnly) return false; + return false; +} + +bool FATFS::setGid(FSNode* node, u32int gid) { + if (m_readOnly) return false; + return false; +} + +bool FATFS::setParent(FSNode* node, FSNode* parent) { + if (m_readOnly) return false; + return false; +} + +u32int FATFS::read(FileNode* file, u64int position, u32int max_length, u8int *data) { + u32int len = max_length; + if (position >= file->getLength()) return 0; + if (position + len > file->getLength()) len = file->getLength() - position; + u32int firstCluster = position / m_clusterSize, clusterOffset = position % m_clusterSize; + u32int clusters = (len + clusterOffset) / m_clusterSize + 1, lastClusBytesToRead = (len + clusterOffset) % m_clusterSize; + u32int clust = FIRSTCLUS(file); + //Find first cluster + for (u32int i = 0; i < firstCluster and clust != 0; i++) clust = nextCluster(clust); + if (clust == 0) return 0; + //Read first cluster + u8int* temp = (u8int*)Mem::alloc(m_clusterSize); + readCluster(clust, temp); + memcpy(data, temp + clusterOffset, (len > m_clusterSize - clusterOffset ? m_clusterSize - clusterOffset : len)); + //Read next cluster + u32int pos = (m_clusterSize - clusterOffset); + for (u32int i = 1; i < clusters; i++) { + clust = nextCluster(clust); + if (clust == 0) break; + readCluster(clust, temp); + memcpy(data + pos, temp, (i == clusters - 1 ? lastClusBytesToRead : m_clusterSize)); + pos += m_clusterSize; + } + Mem::free(temp); + return len; +} + +bool FATFS::write(FileNode* file, u64int position, u32int length, u8int* data) { + if (m_readOnly) return false; + return false; +} + +bool FATFS::truncate(FileNode* file) { + if (m_readOnly) return false; + return false; +} + +bool FATFS::loadContents(DirectoryNode* dir) { + u32int cluster = FIRSTCLUS(dir); + union { + u8int *c; + fat_dir_entry_t *e; + } e; + + u32int entries = m_clusterSize / sizeof(fat_dir_entry_t); + if (cluster == 2 and m_fatType != 32) { //This is the value we use for the root directory + e.c = (u8int*)Mem::alloc(m_rootDirSectors * m_part->blockSize()); + if (!m_part->readBlocks(m_firstDataSector, m_rootDirSectors, e.c)) return false; + } else { + e.c = (u8int*)Mem::alloc(m_clusterSize); + } + + ByteArray lfnBuffer; + while (cluster != 0) { + if (cluster != 2 or m_fatType == 32) { + if (!readCluster(cluster, e.c)) return false; + } + for (u32int i = 0; i < entries; i++) { + if (e.e[i].attributes == FA_LFN && e.c[i*32] != 0xE5) { //Long file name entry + u8int num = e.c[i*32] & 0x3; + if (lfnBuffer.size() < num * 26) lfnBuffer.resize(num * 26); + num--; + memcpy(lfnBuffer + (num * 26), e.c + (i*32 + 1), 10); + memcpy(lfnBuffer + (num * 26 + 10), e.c + (i*32 + 14), 12); + memcpy(lfnBuffer + (num * 26 + 22), e.c + (i*32 + 28), 4); + } + if (e.e[i].attributes & FA_VOLUMEID) continue; + if (e.e[i].name[0] == 0 or e.e[i].name[0] == 0xE5) continue; //Nothing intresting here. + String name; + if (lfnBuffer.empty()) { + for (int j = 0; j < 8; j++) { + if (e.e[i].name[j] == ' ') break; + name += WChar(e.e[i].name[j]); + } + for (int j = 0; j < 3; j++) { + if (e.e[i].extension[j] == ' ') break; + if (j == 0) name += "."; + name += WChar(e.e[i].extension[j]); + } + } else { + name = lfnBuffer.toString(UE_UTF16_LE); + lfnBuffer.clear(); + } + u32int first_clus = (e.e[i].first_clust_high << 16) + e.e[i].first_clust_low; + FSNode* n; + if (e.e[i].attributes & FA_DIRECTORY) { + if (name == "." or name == "..") continue; + n = new FATDirectoryNode(name, this, dir); + } else { + n = new FATFileNode(name, this, dir, e.e[i].size); + } + FIRSTCLUS(n) = first_clus; + dir->getChildren().push(n); + } + if (cluster == 2 && m_fatType != 32) break; //We are in a FAT12/16 root directory + cluster = nextCluster(cluster); + } + + Mem::free(e.c); + return true; +} + +FileNode* FATFS::createFile(DirectoryNode* parent, String name) { + if (m_readOnly) return false; + return 0; +} + +DirectoryNode* FATFS::createDirectory(DirectoryNode* parent, String name) { + if (m_readOnly) return false; + return 0; +} + +bool FATFS::remove(DirectoryNode* parent, FSNode* node) { + if (m_readOnly) return false; + return false; +} diff --git a/Source/Kernel/FileSystems/FAT/FATFS.class.h b/Source/Kernel/FileSystems/FAT/FATFS.class.h new file mode 100644 index 0000000..fbefc02 --- /dev/null +++ b/Source/Kernel/FileSystems/FAT/FATFS.class.h @@ -0,0 +1,134 @@ +#ifndef DEF_FATFS_CLASS_H +#define DEF_FATFS_CLASS_H + +#include <VFS/FileSystem.proto.h> +#include <VFS/Part.ns.h> +#include <VFS/BlockCache.class.h> + +struct fat_extBS_32_t { //Extended boot sector for FAT32 + unsigned int table_size_32; + unsigned short extended_flags; + unsigned short fat_version; + unsigned int root_cluster; + unsigned short fat_info; + unsigned short backup_BS_sector; + unsigned char reserved_0[12]; + unsigned char drive_number; + unsigned char reserved_1; + unsigned char boot_signature; + unsigned int volume_id; + unsigned char volume_label[11]; + unsigned char fat_type_label[8]; +}__attribute__((packed)); + +struct fat_extBS_16_t { //Extended boot sector for FAT12 and FAT16 + unsigned char bios_drive_num; + unsigned char reserved1; + unsigned char boot_signature; + unsigned int volume_id; + unsigned char volume_label[11]; + unsigned char fat_type_label[8]; +}__attribute__((packed)); + +struct fat_BS_t { //Boot sector + unsigned char bootjmp[3]; + unsigned char oem_name[8]; + unsigned short bytes_per_sector; + unsigned char sectors_per_cluster; + unsigned short reserved_sector_count; + unsigned char table_count; + unsigned short root_entry_count; + unsigned short total_sectors_16; + unsigned char media_type; + unsigned short table_size_16; + unsigned short sectors_per_track; + unsigned short head_side_count; + unsigned int hidden_sector_count; + unsigned int total_sectors_32; + union { + fat_extBS_32_t extBS_32; + fat_extBS_16_t extBS_16; + }; +}__attribute__((packed)); + +struct fat_date_t { + u16int year : 7; + u16int month : 4; + u16int day : 5; +}__attribute__((packed)); + +struct fat_time_t { + u16int hour : 5; + u16int minutes : 6; + u16int seconds : 5; +}__attribute__((packed)); + +struct fat_dir_entry_t { + char name[8]; + char extension[3]; + u8int attributes; + u8int reserved; + u8int createtenthsofseconds; + fat_time_t created_time; + fat_date_t created_date; + fat_date_t accessed_date; + u16int first_clust_high; //always 0 on FAT12/16 + fat_time_t modified_time; + fat_date_t modified_date; + u16int first_clust_low; + u32int size; +}__attribute__((packed)); + +#define FA_READONLY 0x01 +#define FA_HIDDEN 0x02 +#define FA_SYSTEM 0x04 +#define FA_VOLUMEID 0x08 +#define FA_DIRECTORY 0x10 +#define FA_ARCHIVE 0x20 +#define FA_LFN 0x0F + +class FATFS : public FileSystem { + private: + fat_BS_t m_bs; + bool m_readOnly; + u32int m_fatSize; //Size of one FAT, in sectors + u32int m_totalSectors; //Total sectors used by the FAT + u32int m_rootDirSectors; //Sectors used by the root directory + u32int m_firstDataSector; //First data sector, start of cluster 2 + u32int m_countOfClusters; //Count of usable clusters, EXCLUDING the ones used by the root directory + u32int m_clusterSize; //size of a cluster in bytes + u32int m_fatType; //12, 16 or 32 + Partition* m_part; + BlockCache<Partition> m_fatCache; + + u32int nextCluster(u32int cluster); //Get the next cluster number in the chain (0 = EOF) + bool readCluster(u32int cluster, u8int* data); //Read the content of a cluster to a buffer + + ~FATFS() {} + FATFS(Partition* p) : m_part(p), m_fatCache(p) {} + + public: + static FileSystem* mount(Partition* p, DirectoryNode* mountpoint, bool readwrite = false); + + bool unmount(); + + String getDevDescription() { return Part::partIdentifier(m_part); } + + bool setName(FSNode* node, String name); + bool setPermissions(FSNode* node, u32int permissions); + bool setUid(FSNode* node, u32int uid); + bool setGid(FSNode* node, u32int gid); + bool setParent(FSNode* node, FSNode* parent); + + u32int read(FileNode* file, u64int position, u32int max_length, u8int *data); + bool write(FileNode* file, u64int position, u32int length, u8int *data); + bool truncate(FileNode* file); + + bool loadContents(DirectoryNode* dir); + FileNode* createFile(DirectoryNode* parent, String name); + DirectoryNode* createDirectory(DirectoryNode* parent, String name); + bool remove(DirectoryNode* parent, FSNode* node); +}; + +#endif + diff --git a/Source/Kernel/FileSystems/FAT/FATFileNode.class.h b/Source/Kernel/FileSystems/FAT/FATFileNode.class.h new file mode 100644 index 0000000..b64f911 --- /dev/null +++ b/Source/Kernel/FileSystems/FAT/FATFileNode.class.h @@ -0,0 +1,16 @@ +#ifndef DEF_FATFILENODE_CLASS_H +#define DEF_FATFILENODE_CLASS_H + +#include <VFS/FileNode.class.h> + +class FATFileNode : public FileNode { + friend class FATFS; + FATFileNode (String name, FileSystem* fs, FSNode* parent, u32int size, u32int permissions = 0777, + u32int uid = 0, u32int gid = 0) : + FileNode(name, fs, parent, size, permissions, uid, gid){} + + u32int m_firstCluster; + u32int m_firstDirEntryID; //id of the first directory entry corresponding to this file in parent directory +}; + +#endif diff --git a/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp b/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp index 5997841..e6370d0 100644 --- a/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp +++ b/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp @@ -1,30 +1,36 @@ #include "RamFS.class.h" #include <VFS/DirectoryNode.class.h> #include "RamFileNode.class.h" +#include <VFS/VFS.ns.h> RamFS::RamFS() { } RamFS::~RamFS() { - delete m_rootNode; } RamFS* RamFS::mount(u32int maxSize, DirectoryNode* mountpoint) { + if (mountpoint != 0 and !mountpoint->mountpointable()) return 0; RamFS* rfs = new RamFS(); rfs->m_maxSize = maxSize; rfs->m_usedSize = 0; rfs->m_isWritable = true; rfs->m_rootNode = new DirectoryNode("/", rfs, mountpoint); + if (mountpoint != 0) mountpoint->mount(rfs->m_rootNode); + VFS::registerFilesystem(rfs); return rfs; } RamFS* RamFS::mount(u8int *ptr, u32int maxSize, DirectoryNode* mountpoint, bool writable) { + if (mountpoint != 0 and !mountpoint->mountpointable()) return 0; RamFS* rfs = new RamFS(); rfs->m_maxSize = maxSize; rfs->m_usedSize = 0; rfs->m_isWritable = true; rfs->m_rootNode = new DirectoryNode("/", rfs, mountpoint); + if (mountpoint != 0) mountpoint->mount(rfs->m_rootNode); + VFS::registerFilesystem(rfs); union { u8int* c; @@ -81,7 +87,7 @@ RamFS* RamFS::mount(u8int *ptr, u32int maxSize, DirectoryNode* mountpoint, bool } bool RamFS::unmount() { - return m_rootNode->unmountable(); + return true; } bool RamFS::setName(FSNode* node, String name) { return true; } @@ -164,6 +170,7 @@ bool RamFS::remove(DirectoryNode* parent, FSNode* node) { if (node->type() == NT_FILE) { u8int *d = ((RamFileNode*)node)->m_data; if (d != 0) Mem::free(d); + ((RamFileNode*)node)->m_data = 0; } return true; } diff --git a/Source/Kernel/FileSystems/RamFS/RamFS.class.h b/Source/Kernel/FileSystems/RamFS/RamFS.class.h index 1d60796..042baa9 100644 --- a/Source/Kernel/FileSystems/RamFS/RamFS.class.h +++ b/Source/Kernel/FileSystems/RamFS/RamFS.class.h @@ -17,10 +17,10 @@ struct initrd_file_header { class RamFS : public FileSystem { private: - ~RamFS(); + virtual ~RamFS(); RamFS(const RamFS& other); RamFS(); - bool unmount(); //TO BE USED ONLY BY VFS::UNMOUNT (when will exist...) + bool unmount(); u32int m_maxSize; u32int m_usedSize; @@ -35,6 +35,8 @@ class RamFS : public FileSystem { bool setGid(FSNode* node, u32int gid); bool setParent(FSNode* node, FSNode* parent); + String getDevDescription() { return "ramfs"; } + u32int read(FileNode* file, u64int position, u32int max_length, u8int *data); bool write(FileNode* file, u64int position, u32int length, u8int *data); bool truncate(FileNode* file); diff --git a/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h b/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h index d600630..2abad64 100644 --- a/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h +++ b/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h @@ -11,6 +11,8 @@ class RamFileNode : public FileNode { u32int uid = 0, u32int gid = 0) : FileNode(name, fs, parent, 0, permissions, uid, gid), m_data(0) {} + ~RamFileNode() { if (m_data != 0) delete m_data; } + u8int *m_data; //We don't take care of allocation/freeing here, RamFS:: does that for us void setLength(u32int length) { m_length = length; } diff --git a/Source/Kernel/Linker/ElfBinary.class.cpp b/Source/Kernel/Linker/ElfBinary.class.cpp index 27e5474..0518c38 100644 --- a/Source/Kernel/Linker/ElfBinary.class.cpp +++ b/Source/Kernel/Linker/ElfBinary.class.cpp @@ -9,7 +9,7 @@ ElfBinary::~ElfBinary() { Binary* ElfBinary::load(File& file) { elf_ehdr_t hdr; - file.read<elf_ehdr_t> (&hdr); + if (!file.read<elf_ehdr_t> (&hdr)) return 0; //Verify we have an elf file if (hdr.e_ident[0] != 0x7F or hdr.e_ident[1] != 'E' or hdr.e_ident[2] != 'L' or hdr.e_ident[3] != 'F') return 0; diff --git a/Source/Kernel/Linker/MelonBinary.class.cpp b/Source/Kernel/Linker/MelonBinary.class.cpp index 0737b71..8a85977 100644 --- a/Source/Kernel/Linker/MelonBinary.class.cpp +++ b/Source/Kernel/Linker/MelonBinary.class.cpp @@ -2,7 +2,7 @@ Binary* MelonBinary::load(File& file) { u32int magic; - file.read<u32int>(&magic); + if (!file.read<u32int>(&magic)) return 0; if (magic == 0xFEEDBEEF) { MelonBinary* r = new MelonBinary; file.read<u32int>(&r->m_size); diff --git a/Source/Kernel/Makefile b/Source/Kernel/Makefile index a70c8c5..2005cd2 100644 --- a/Source/Kernel/Makefile +++ b/Source/Kernel/Makefile @@ -66,6 +66,7 @@ Objects = Core/loader.wtf.o \ VFS/DirectoryNode.class.o \ UserManager/Usr.ns.o \ FileSystems/RamFS/RamFS.class.o \ + FileSystems/FAT/FATFS.class.o \ SyscallManager/IDT.ns.o \ SyscallManager/Ressource.class.o \ SyscallManager/Res.ns.o \ diff --git a/Source/Kernel/Shell/KernelShell-fs.class.cpp b/Source/Kernel/Shell/KernelShell-fs.class.cpp index fa2078d..c389d45 100644 --- a/Source/Kernel/Shell/KernelShell-fs.class.cpp +++ b/Source/Kernel/Shell/KernelShell-fs.class.cpp @@ -125,3 +125,21 @@ void KernelShell::run(Vector<String>& args) { } } } + +void KernelShell::hexdump(Vector<String>& args) { + if (args.size() == 1) { + *m_vt << "No file to hexdump.\n"; + } else { + for (u32int i = 1; i < args.size(); i++) { + File f(args[i], FM_READ, m_cwd); + if (f.valid()) { + u8int *buff = (u8int*)Mem::alloc(f.length()); + f.read(f.length(), buff); + m_vt->hexDump(buff, f.length()); + Mem::free(buff); + } else { + *m_vt << "Error reading from file " << args[i] << "\n"; + } + } + } +} diff --git a/Source/Kernel/Shell/KernelShell-sys.class.cpp b/Source/Kernel/Shell/KernelShell-sys.class.cpp index 6243b0f..06af11d 100644 --- a/Source/Kernel/Shell/KernelShell-sys.class.cpp +++ b/Source/Kernel/Shell/KernelShell-sys.class.cpp @@ -4,6 +4,8 @@ #include <MemoryManager/Mem.ns.h> #include <MemoryManager/PhysMem.ns.h> #include <VFS/Part.ns.h> +#include <VFS/VFS.ns.h> +#include <FileSystems/RamFS/RamFS.class.h> void KernelShell::devices(Vector<String>& args) { Vector<Device*> dev = Dev::findDevices(); @@ -58,3 +60,42 @@ void KernelShell::part(Vector<String>& args) { } } } + +void KernelShell::mount(Vector<String>& args) { + if (args.size() == 1) { + for (u32int i = 0; i < VFS::filesystems.size(); i++) { + *m_vt << VFS::filesystems[i]->getDevDescription() << " on " << VFS::path(VFS::filesystems[i]->getRootNode()) << "\n"; + } + } else if (args.size() == 2) { + if (args[1] == "help") { + *m_vt << "Usage: mount [help|<options>]\n" << + "Options formats :\n" << + " - <mountpoint>:ramfs\n" << + " - <mountpoint>:[<dev_class>]:<dev_number>:<part_number>[:<type>[:[ro|rw]]]\n" << + "You can have a list of available block devices and partitions by typing 'part'.\n"; + } else { + if (VFS::mount(args[1], m_vt)) *m_vt << "Ok, filesystem mounted.\n"; + } + } else { + *m_vt << "Usage: mount [<device> <mountpoint>\n"; + } +} + +void KernelShell::readblock(Vector<String>& args) { + if (args.size() == 3) { + Vector<Device*> devcs = Dev::findDevices("block"); + u32int id = args[1].toInt(), block = args[2].toInt(); + if (id < devcs.size()) { + BlockDevice* bdev = (BlockDevice*)devcs[id]; + *m_vt << "Block " << block << " from device " << bdev->getName() << " (" << bdev->getClass() << ")\n"; + u8int* buff = (u8int*)Mem::alloc(bdev->blockSize()); + bdev->readBlocks(block, 1, buff); + m_vt->hexDump(buff, 32); + Mem::free(buff); + } else { + *m_vt << "Block device #" << id << " does not exist.\n"; + } + } else { + *m_vt << "Usage: readblock <dev id> <block id>\n"; + } +} diff --git a/Source/Kernel/Shell/KernelShell.class.cpp b/Source/Kernel/Shell/KernelShell.class.cpp index d62d822..71a717a 100644 --- a/Source/Kernel/Shell/KernelShell.class.cpp +++ b/Source/Kernel/Shell/KernelShell.class.cpp @@ -3,8 +3,8 @@ #include <DeviceManager/Kbd.ns.h> #include <SimpleList.class.h> #include <MemoryManager/PhysMem.ns.h> -#include <VFS/VFS.ns.h> #include <TaskManager/Task.ns.h> +#include <VFS/VFS.ns.h> u32int KernelShell::m_instances = 0; @@ -60,6 +60,9 @@ u32int KernelShell::run() { {"free", &KernelShell::free}, {"uptime", &KernelShell::uptime}, {"part", &KernelShell::part}, + {"readblock", &KernelShell::readblock}, + {"mount", &KernelShell::mount}, + {"hexdump", &KernelShell::hexdump}, {0, 0} }; @@ -81,6 +84,9 @@ u32int KernelShell::run() { *m_vt << " - free shows memory usage (frames and kheap)\n"; *m_vt << " - uptime shows seconds since boot\n"; *m_vt << " - part shows all detected block devs and partitions\n"; + *m_vt << " - mount shows mounted devices or mounts a ramfs\n"; + *m_vt << " - readblock reads a block from a block device and dumps it\n"; + *m_vt << " - hexdump shows a hexadecimal dump of a file\n"; *m_vt << " - Standard UNIX commands : ls cd cat pwd rm mkdir wf\n"; *m_vt << " - Scroll up with shift+pgup !\n"; } else if (tokens[0] == "reboot") { @@ -92,6 +98,26 @@ u32int KernelShell::run() { } else if (tokens[0] == "exit") { if (tokens.size() == 1) return 0; return tokens[1].toInt(); + } else if (tokens[0] == "unmount") { + if (tokens.size() == 2) { + FSNode* n = VFS::find(tokens[1], m_cwd); + bool ok = false; + if (n == 0) { + ok = false; + } else { + String p = VFS::path(n); + for (u32int i = 0; i < VFS::filesystems.size(); i++) { + if (VFS::path(VFS::filesystems[i]->getRootNode()) == p) { + ok = VFS::unmount(VFS::filesystems[i]); + break; + } + } + } + if (ok) *m_vt << "Ok, filesystem unmounted.\n"; + else *m_vt << "Error.\n"; + } else { + *m_vt << "Usage: unmount <mountpoint>\n"; + } } else if (tokens[0] != "" or tokens.size() != 1) { u32int i = 0; bool found = false; diff --git a/Source/Kernel/Shell/KernelShell.class.h b/Source/Kernel/Shell/KernelShell.class.h index e7549c2..9655def 100644 --- a/Source/Kernel/Shell/KernelShell.class.h +++ b/Source/Kernel/Shell/KernelShell.class.h @@ -27,6 +27,7 @@ class KernelShell { void rm(Vector<String>& args); void wf(Vector<String>& args); void run(Vector<String>& args); + void hexdump(Vector<String>& args); //in KernelShell-sys void devices(Vector<String>& args); @@ -34,6 +35,8 @@ class KernelShell { void free(Vector<String>& args); void uptime(Vector<String>& args); void part(Vector<String>& args); + void readblock(Vector<String>& args); + void mount(Vector<String>& args); void setup(DirectoryNode* cwd, VirtualTerminal *vt); diff --git a/Source/Kernel/UserManager/Usr.ns.cpp b/Source/Kernel/UserManager/Usr.ns.cpp index ecf9bae..66e159e 100644 --- a/Source/Kernel/UserManager/Usr.ns.cpp +++ b/Source/Kernel/UserManager/Usr.ns.cpp @@ -26,11 +26,13 @@ void load() { if (VFS::find("/System/Configuration/Groups")) VFS::find("/System/Configuration/Groups")->setPermissions(0600); if (VFS::find("/System/Configuration/Users")) VFS::find("/System/Configuration/Users")->setPermissions(0600); TextFile groups("/System/Configuration/Groups", FM_READ); - while (!groups.eof()) { - String s = groups.readLine(); - Vector<String> data = s.split(":"); - if (data.size() == 2 and !(s[0] == WChar("#"))) { - m_groups = m_groups->cons(Group(data[1], data[0].toInt())); + if (groups.valid()) { + while (!groups.eof()) { + String s = groups.readLine(); + Vector<String> data = s.split(":"); + if (data.size() == 2 and !(s[0] == WChar("#"))) { + m_groups = m_groups->cons(Group(data[1], data[0].toInt())); + } } } if (m_groups == 0) { @@ -39,12 +41,14 @@ void load() { } TextFile users("/System/Configuration/Users", FM_READ); - while (!users.eof()) { - String s = users.readLine(); - if (s == "" or s[0] == WChar("#")) continue; - Vector<String> data = s.split(":"); - if (data.size() == 6) { - m_users = m_users->cons(User(data[1], data[4], data[5], group(data[2].toInt()), data[3], data[0].toInt())); + if (users.valid()) { + while (!users.eof()) { + String s = users.readLine(); + if (s == "" or s[0] == WChar("#")) continue; + Vector<String> data = s.split(":"); + if (data.size() == 6) { + m_users = m_users->cons(User(data[1], data[4], data[5], group(data[2].toInt()), data[3], data[0].toInt())); + } } } if (m_users == 0) { diff --git a/Source/Kernel/VFS/BlockCache.class.cpp b/Source/Kernel/VFS/BlockCache.class.cpp new file mode 100644 index 0000000..d505a99 --- /dev/null +++ b/Source/Kernel/VFS/BlockCache.class.cpp @@ -0,0 +1,89 @@ +#include <DeviceManager/Time.ns.h> + +template <typename T> +BlockCache<T>::BlockCache(T* dev) { + m_dev = dev; + m_count = 0; +} + +template <typename T> +BlockCache<T>::~BlockCache() { + sync(); + m_count = 0; + delete m_cache; + delete m_cacheInfo; +} + +template <typename T> +void BlockCache<T>::sync() { + for (u32int i = 0; i < m_count; i++) { + if (m_cacheInfo[i].dirty) m_dev->writeBlocks(m_cacheInfo[i].id, 1, m_cache + (i * m_dev->blockSize())); + } +} + +template <typename T> +void BlockCache<T>::init(u32int count) { + m_count = count; + m_cacheInfo = new cached_block_t[count]; + for (u32int i = 0; i < m_count; i++) { + m_cacheInfo[i].id = 0; + m_cacheInfo[i].lastuse = 0; + m_cacheInfo[i].dirty = false; + } + m_cache = (u8int*)Mem::alloc(m_count * m_dev->blockSize()); +} + +template <typename T> +bool BlockCache<T>::setCache(u64int block, u8int* data, bool dirty) { + u32int best = 0; + for (u32int i = 0; i < m_count; i++) { + if (m_cacheInfo[i].id == block) { + best = i; + break; + } + if (m_cacheInfo[i].lastuse < m_cacheInfo[best].lastuse) best = i; + } + if (best >= m_count) return false; + if (m_cacheInfo[best].dirty && (m_cacheInfo[best].id != block or !dirty)) + m_dev->writeBlocks(m_cacheInfo[best].id, 1, m_cache + (best * m_dev->blockSize())); + m_cacheInfo[best].id = block; + m_cacheInfo[best].lastuse = Time::uptime(); + m_cacheInfo[best].dirty = dirty; + memcpy(m_cache + (best * m_dev->blockSize()), data, m_dev->blockSize()); + return true; +} + +template <typename T> +bool BlockCache<T>::getCache(u64int block, u8int* data) { + for (u32int i = 0; i < m_count; i++) { + if (m_cacheInfo[i].id == block && m_cacheInfo[i].lastuse != 0) { + m_cacheInfo[i].lastuse = Time::uptime(); + memcpy(data, m_cache + (i * m_dev->blockSize()), m_dev->blockSize()); + return true; + } + } + return false; +} + +template <typename T> +bool BlockCache<T>::readBlocks(u64int startblock, u32int count, u8int* data) { + if (count == 1) { + if (getCache(startblock, data)) return true; + if (!m_dev->readBlocks(startblock, count, data)) return false; + setCache(startblock, data); + return true; + } else { + return m_dev->readBlocks(startblock, count, data); + } +} + +template <typename T> +bool BlockCache<T>::writeBlocks(u64int startblock, u32int count, u8int* data) { + if (m_dev->readOnly()) return false; + if (count == 1) { + if (!setCache(startblock, data, true)) return m_dev->writeBlocks(startblock, count, data); + return true; + } else { + return m_dev->writeBlocks(startblock, count, data); + } +} diff --git a/Source/Kernel/VFS/BlockCache.class.h b/Source/Kernel/VFS/BlockCache.class.h new file mode 100644 index 0000000..0b26180 --- /dev/null +++ b/Source/Kernel/VFS/BlockCache.class.h @@ -0,0 +1,32 @@ +#ifndef DEF_BLOCKCACHE_CLASS_H +#define DEF_BLOCKCACHE_CLASS_H + +template <typename T> +class BlockCache { + private: + T* m_dev; + u32int m_count; + struct cached_block_t { + u64int id; + u32int lastuse; + bool dirty; + } *m_cacheInfo; + u8int* m_cache; + + void sync(); + bool setCache(u64int block, u8int* data, bool dirty = false); + bool getCache(u64int block, u8int* data); + + public: + BlockCache(T* dev); + ~BlockCache(); + void init(u32int count); + + bool readBlocks(u64int startblock, u32int count, u8int* data); + bool writeBlocks(u64int startblock, u32int count, u8int* data); + +}; + +#include "BlockCache.class.cpp" + +#endif diff --git a/Source/Kernel/VFS/DirectoryNode.class.cpp b/Source/Kernel/VFS/DirectoryNode.class.cpp index 74c1ff8..55365f0 100644 --- a/Source/Kernel/VFS/DirectoryNode.class.cpp +++ b/Source/Kernel/VFS/DirectoryNode.class.cpp @@ -6,6 +6,15 @@ call_t DirectoryNode::m_callTable[] = { CALL0(0, 0) }; +DirectoryNode::~DirectoryNode() { + if (m_contentLoaded) { + for (u32int i = 0; i < m_children.size(); i++) { + delete m_children[i]; + } + } + if (m_name == "/" && m_parent != NULL) ((DirectoryNode*)(m_parent))->unmount(); +} + u32int DirectoryNode::getIdxChildSC(u32int idx) { if (!runnable()) return (u32int) - 1; FSNode* n = getChild(idx); @@ -21,15 +30,29 @@ u32int DirectoryNode::getNameChildSC(u32int name) { return (u32int) - 1; } +u64int DirectoryNode::getLength() { + if (m_mounts != 0) return m_mounts->getLength(); + if (!m_contentLoaded) + if (!loadContent()) + return 0; + return m_length; +} + +FSNode* DirectoryNode::getParent() { + //if (m_name == "/" and m_parent != 0) return m_parent->getParent(); + return m_parent; +} + bool DirectoryNode::removable() { if (!m_contentLoaded) if (!loadContent()) return false; - return m_children.empty(); + return m_children.empty() && (m_mounts == 0); } bool DirectoryNode::unmountable() { if (!m_contentLoaded) return true; + if (m_mounts != 0) return false; for (u32int i = 0; i < m_children.size(); i++) { if (m_children[i]->type() == NT_DIRECTORY) { if (!((DirectoryNode*)m_children[i])->unmountable()) return false; @@ -40,7 +63,22 @@ bool DirectoryNode::unmountable() { return true; } +bool DirectoryNode::mountpointable() { + if (!m_contentLoaded) + if (!loadContent()) return false; + return m_children.empty(); +} + +void DirectoryNode::mount(DirectoryNode* childRoot) { + m_mounts = childRoot; +} + +void DirectoryNode::unmount() { + m_mounts = 0; +} + bool DirectoryNode::loadContent() { + if (m_mounts != 0) return m_mounts->loadContent(); if (m_contentLoaded) return true; bool b = m_fs->loadContents(this); if (!b) return false; @@ -50,6 +88,7 @@ bool DirectoryNode::loadContent() { } FSNode* DirectoryNode::getChild(u32int index) { + if (m_mounts != 0) return m_mounts->getChild(index); if (!m_contentLoaded) if (!loadContent()) return NULL; @@ -58,6 +97,7 @@ FSNode* DirectoryNode::getChild(u32int index) { } FSNode* DirectoryNode::getChild(const String& name) { + if (m_mounts != 0) return m_mounts->getChild(name); if (!m_contentLoaded) if (!loadContent()) return NULL; @@ -69,18 +109,21 @@ FSNode* DirectoryNode::getChild(const String& name) { } FileNode* DirectoryNode::createFile(const String& name) { + if (m_mounts != 0) return m_mounts->createFile(name); FileNode* n = m_fs->createFile(this, name); m_length = m_children.size(); return n; } DirectoryNode* DirectoryNode::createDirectory(const String& name) { + if (m_mounts != 0) return m_mounts->createDirectory(name); DirectoryNode* n = m_fs->createDirectory(this, name); m_length = m_children.size(); return n; } bool DirectoryNode::remove(FSNode* child) { + if (m_mounts != 0) return m_mounts->remove(child); //Check node is indeed one of our childs if (!m_contentLoaded) if (!loadContent()) diff --git a/Source/Kernel/VFS/DirectoryNode.class.h b/Source/Kernel/VFS/DirectoryNode.class.h index 4d9b211..1fc4c52 100644 --- a/Source/Kernel/VFS/DirectoryNode.class.h +++ b/Source/Kernel/VFS/DirectoryNode.class.h @@ -8,6 +8,7 @@ class DirectoryNode : public FSNode { protected: Vector<FSNode*> m_children; bool m_contentLoaded; + DirectoryNode* m_mounts; //Root node of the filesystem mounted here, null if none //Syscalls static call_t m_callTable[]; @@ -19,20 +20,20 @@ class DirectoryNode : public FSNode { u32int uid = 0, u32int gid = 0) : FSNode(name, fs, parent, 0, permissions, uid, gid), m_children(), m_contentLoaded(false) { addCallTable(m_callTable); + m_mounts = 0; } - virtual ~DirectoryNode() { - if (m_contentLoaded) { - for (u32int i = 0; i < m_children.size(); i++) { - delete m_children[i]; - } - } - } + virtual ~DirectoryNode(); Vector<FSNode*> &getChildren() { return m_children; } //MUST BE USED ONLY BY FILESYSTEMS u8int type() { return NT_DIRECTORY; } + u64int getLength(); + FSNode* getParent(); bool removable(); bool unmountable(); + bool mountpointable(); + void mount(DirectoryNode* childRoot); + void unmount(); bool loadContent(); FSNode* getChild(u32int index); diff --git a/Source/Kernel/VFS/FSNode.proto.h b/Source/Kernel/VFS/FSNode.proto.h index 0aafc8a..a46c79d 100644 --- a/Source/Kernel/VFS/FSNode.proto.h +++ b/Source/Kernel/VFS/FSNode.proto.h @@ -44,12 +44,12 @@ class FSNode : public Ressource { virtual bool used() { return false; } //True if file is read/written from/to const String& getName() { return m_name; } - u64int getLength() { return m_length; } + virtual u64int getLength() { return m_length; } u32int getPermissions() { return m_permissions; } u32int getUid() { return m_uid; } u32int getGid() { return m_gid; } FileSystem *getFS() { return m_fs; } - FSNode* getParent() { return m_parent; } + virtual FSNode* getParent() { return m_parent; } //Helper functions bool readable(User* user = 0); diff --git a/Source/Kernel/VFS/File.class.cpp b/Source/Kernel/VFS/File.class.cpp index c5ddcd6..84561a5 100644 --- a/Source/Kernel/VFS/File.class.cpp +++ b/Source/Kernel/VFS/File.class.cpp @@ -33,7 +33,7 @@ bool File::open(String filename, u8int mode, FSNode* start, bool vrfyperm) { if (node == NULL){ if (mode == FM_READ) return false; node = VFS::createFile(filename, start, vrfyperm); - if (node == 0) return false; + if (node == NULL) return false; } if (node->type() != NT_FILE) return false; @@ -137,6 +137,7 @@ bool File::seek(u64int count, u8int mode) { } bool File::eof() { + if (!m_valid) return false; return m_position == m_file->getLength(); } diff --git a/Source/Kernel/VFS/FileSystem.proto.h b/Source/Kernel/VFS/FileSystem.proto.h index a614c13..9216219 100644 --- a/Source/Kernel/VFS/FileSystem.proto.h +++ b/Source/Kernel/VFS/FileSystem.proto.h @@ -5,20 +5,29 @@ class FSNode; class FileNode; class DirectoryNode; +class FileSystem; + +namespace VFS { + bool unmount(FileSystem*); +} //This abstract class describes a filesystem class FileSystem { + friend bool VFS::unmount(FileSystem*); + protected: - virtual ~FileSystem() {} + virtual ~FileSystem(); bool m_isWritable; //false = read only DirectoryNode* m_rootNode; - public: - bool unmount(); + virtual bool unmount() = 0; //Sync data with the disk + public: bool isWritable() { return m_isWritable; } DirectoryNode* getRootNode() { return m_rootNode; } + virtual String getDevDescription() = 0; + //Must be implemented by the filesystem virtual bool setName(FSNode* node, String name) = 0; virtual bool setPermissions(FSNode* node, u32int permissions) = 0; diff --git a/Source/Kernel/VFS/Part.ns.cpp b/Source/Kernel/VFS/Part.ns.cpp index 6408dbd..9ead6b5 100644 --- a/Source/Kernel/VFS/Part.ns.cpp +++ b/Source/Kernel/VFS/Part.ns.cpp @@ -56,4 +56,36 @@ u32int getDeviceID(BlockDevice* dev) { return (u32int) - 1; } +BlockDevice* dev(String _class, u32int idx) { + if (_class.empty()) return devices[idx]; + for (u32int i = 0; i < devices.size(); i++) { + String devclass = devices[i]->getClass(); + if (devclass == _class or (devclass.size() > _class.size() and devclass.substr(0, _class.size()) == _class)) { + if (idx == 0) { + return devices[i]; + } else { + idx--; + } + } + } + return NULL; +} + +Partition* part(BlockDevice* dev, u32int idx) { + for (u32int i = 0; i < partitions.size(); i++) { + if (partitions[i]->getDevice() == dev) { + if (idx == 0) { + return partitions[i]; + } else { + idx--; + } + } + } + return NULL; +} + +String partIdentifier(Partition* p) { + return String("d") += String::number(getDeviceID(p->getDevice())) += String("p") += String::number(p->getPartNumber()); +} + } diff --git a/Source/Kernel/VFS/Part.ns.h b/Source/Kernel/VFS/Part.ns.h index 40a0fb2..992f6f3 100644 --- a/Source/Kernel/VFS/Part.ns.h +++ b/Source/Kernel/VFS/Part.ns.h @@ -13,6 +13,11 @@ namespace Part { void unregisterDevice(BlockDevice* dev); u32int getDeviceID(BlockDevice* dev); + + BlockDevice* dev(String _class, u32int idx); + Partition* part(BlockDevice* dev, u32int idx); + + String partIdentifier(Partition* p); //Simply to help recognize the partition } #endif diff --git a/Source/Kernel/VFS/Partition.class.cpp b/Source/Kernel/VFS/Partition.class.cpp index b62f33c..8d7de9b 100644 --- a/Source/Kernel/VFS/Partition.class.cpp +++ b/Source/Kernel/VFS/Partition.class.cpp @@ -2,21 +2,23 @@ using namespace CMem; //For memcpy -Partition::Partition(BlockDevice* dev, u8int partnumber, u64int startblock, u64int blockcount) { +Partition::Partition(BlockDevice* dev, u8int partnumber, u64int startblock, u64int blockcount) +: m_cache(dev) { m_device = dev; m_partnumber = partnumber; m_startblock = startblock; m_blockcount = blockcount; + m_cache.init(10 + (m_device->blocks() / 1000 > 100 ? 100 : m_device->blocks() / 1000)); } bool Partition::readBlocks(u64int startblock, u32int count, u8int *data) { if (startblock + count > m_startblock + m_blockcount) return false; - return m_device->readBlocks(startblock - m_startblock, count, data); + return m_cache.readBlocks(startblock - m_startblock, count, data); } bool Partition::writeBlocks(u64int startblock, u32int count, u8int *data) { if (startblock + count > m_startblock + m_blockcount) return false; - return m_device->writeBlocks(startblock - m_startblock, count, data); + return m_cache.writeBlocks(startblock - m_startblock, count, data); } bool Partition::read(u64int start, u32int length, u8int *data) { @@ -65,4 +67,4 @@ BlockDevice* Partition::getDevice() { return m_device; } u64int Partition::getStartBlock() { return m_startblock; } u64int Partition::getBlockCount() { return m_blockcount; } u8int Partition::getPartNumber() { return m_partnumber; } -u32int Partition::getBlockSize() { return m_device->blockSize(); } +u32int Partition::blockSize() { return m_device->blockSize(); } diff --git a/Source/Kernel/VFS/Partition.class.h b/Source/Kernel/VFS/Partition.class.h index 8df1c4f..eb0aafd 100644 --- a/Source/Kernel/VFS/Partition.class.h +++ b/Source/Kernel/VFS/Partition.class.h @@ -2,10 +2,12 @@ #define DEF_PARTITION_CLASS_H #include <Devices/BlockDevice.proto.h> +#include <VFS/BlockCache.class.h> class Partition { private: BlockDevice* m_device; + BlockCache<BlockDevice> m_cache; u64int m_startblock, m_blockcount; u8int m_partnumber; //Partition number in partition table of device @@ -24,7 +26,7 @@ class Partition { u64int getStartBlock(); u64int getBlockCount(); u8int getPartNumber(); - u32int getBlockSize(); + u32int blockSize(); inline u64int blocks() { return getBlockCount(); } }; diff --git a/Source/Kernel/VFS/VFS.ns.cpp b/Source/Kernel/VFS/VFS.ns.cpp index e95b911..3b59c5a 100644 --- a/Source/Kernel/VFS/VFS.ns.cpp +++ b/Source/Kernel/VFS/VFS.ns.cpp @@ -1,19 +1,114 @@ #include "VFS.ns.h" #include <VFS/FileNode.class.h> +#include <Vector.class.h> +#include <VTManager/VirtualTerminal.proto.h> + +#include <VFS/Part.ns.h> +#include <FileSystems/RamFS/RamFS.class.h> +#include <FileSystems/FAT/FATFS.class.h> + +struct local_fs_t { + const char* name; + mount_callback_t cb; +} fileSystems[] = { + {"fat", FATFS::mount}, + {0, 0} +}; + +FileSystem::~FileSystem() { delete m_rootNode; } namespace VFS { -DirectoryNode *rootNode; +DirectoryNode *rootNode = 0; +Vector<FileSystem*> filesystems; + +DirectoryNode* getRootNode() { + return rootNode; +} + +void registerFilesystem(FileSystem* fs) { + unregisterFilesystem(fs); + filesystems.push(fs); + if (rootNode == 0) rootNode = fs->getRootNode(); +} -//TODO : mount stuff +void unregisterFilesystem(FileSystem* fs) { + for (u32int i = 0; i < filesystems.size(); i++) { + if (filesystems[i] == fs) { + filesystems[i] = filesystems.back(); + filesystems.pop(); + break; + } + } +} -bool setRootNode(DirectoryNode* node) { - rootNode = node; +bool unmount(FileSystem* fs) { + if (!fs->getRootNode()->unmountable()) return false; + if (fs->getRootNode() == rootNode) return false; + if (!fs->unmount()) return false; + delete fs; //Will automatically delete the root node (destructor is in this file); return true; } -DirectoryNode* getRootNode() { - return rootNode; +bool mount(String str, VirtualTerminal* vt, multiboot_info_t *mbd) { + Vector<String> fs = str.split(":"); + DirectoryNode* root; + if (fs[0] == "/") { + root = NULL; + } else { + FSNode* n = VFS::find(fs[0]); + if (n == NULL) { + *vt << "Mountpoint does not exist : " << fs[0] << "\n"; + return false; + } + if (n->type() != NT_DIRECTORY) { + *vt << "Mountpoint is not a directory : " << fs[0] << "\n"; + return false; + } + root = (DirectoryNode*)n; + } + if (fs[1] == "ramfs") { + if (fs.size() > 2) { + if (mbd != 0) { + module_t *mods = (module_t*)mbd->mods_addr; + if (fs[2].toInt() >= mbd->mods_count) { + *vt << "Invalid module number for filesystem to mount on " << fs[0] << "\n"; + return false; + } + RamFS::mount((u8int*)mods[fs[2].toInt()].mod_start, 1024 * 1024, root); + return true; + } else { + *vt << "Cannot mount kernel modules outside of kernel command line.\n"; + return false; + } + } else { + RamFS::mount(1024 * 1024, root); + return true; + } + } else { + if (fs.size() < 4) { + *vt << "Syntax: <mountpoint>:[<dev_class>]:<dev_id>:<part_id>[:<fs_type>[:[ro|rw]]]\n"; + return false; + } + if (fs.size() < 5) fs.push(""); + if (fs.size() < 6) fs.push("ro"); //By default, mount file systems read-only + BlockDevice* d = Part::dev(fs[1], fs[2].toInt()); + Partition* p = Part::part(d, fs[3].toInt()); + for (u32int i = 0; fileSystems[i].cb != 0; i++) { + if (fs[4] == fileSystems[i].name or fs[4] == "") { + if (fileSystems[i].cb(p, root, (fs[5] == "rw")) != NULL) { + return true; + } else if (fs[4] != "") { + *vt << "Could not mount filesystem on " << fs[0] << "\n"; + if (root == NULL) PANIC("Error while mounting root filesystem."); + return false; + } + } + } + *vt << "Unknown filesystem type for filesystem to mount on " << fs[0] << "\n"; + if (root == NULL) PANIC("Unknown filesystem type for root file system."); + return false; + } } FSNode* find(const String& path, FSNode* start) { diff --git a/Source/Kernel/VFS/VFS.ns.h b/Source/Kernel/VFS/VFS.ns.h index f1d628f..eede728 100644 --- a/Source/Kernel/VFS/VFS.ns.h +++ b/Source/Kernel/VFS/VFS.ns.h @@ -1,17 +1,27 @@ #ifndef DEF_VFS_NS_H #define DEF_VFS_NS_H +#include <Core/multiboot.wtf.h> + #include <VFS/DirectoryNode.class.h> #include <VFS/FileSystem.proto.h> +#include <Vector.class.h> -typedef FileSystem* (* mountcallback)(Partition* partition); +typedef FileSystem* (* mount_callback_t)(Partition* partition, DirectoryNode* mountpoint, bool readwrite); namespace VFS { - void registerMountCallback(mountcallback mcb); + extern Vector<FileSystem*> filesystems; + + void registerMountCallback(mount_callback_t mcb); bool mount(Partition* partition, DirectoryNode *mountpoint); - bool setRootNode(DirectoryNode* root); DirectoryNode* getRootNode(); + void registerFilesystem(FileSystem* fs); + void unregisterFilesystem(FileSystem* fs); + bool unmount(FileSystem* fs); + + bool mount(String str, VirtualTerminal* logvt, multiboot_info_t* mbd = 0); + FSNode* find(const String& path, FSNode* start = 0); FSNode* createFile(const String& path, FSNode* start = 0, bool vrfyperm = false); FSNode* createDirectory(const String& path, FSNode* start = 0, bool vrfyperm = false); |