diff options
Diffstat (limited to 'Source')
49 files changed, 1335 insertions, 129 deletions
diff --git a/Source/Applications/Demos/GOL.cpp b/Source/Applications/Demos/GOL.cpp index 32eb30a..e6da3a6 100644 --- a/Source/Applications/Demos/GOL.cpp +++ b/Source/Applications/Demos/GOL.cpp @@ -1,6 +1,7 @@ #include <Binding/VirtualTerminal.class.h> #include <Binding/Thread.class.h> #include <String.class.h> +#include <ByteArray.class.h> #include <Rand.ns.h> int main(Vector<String> args) { @@ -22,7 +23,7 @@ int main(Vector<String> args) { } } - char *tmp = new char[w * h + 1]; + ByteArray tmp((w + 1) * (h + 1)); bool run = true; while (run) { @@ -37,7 +38,7 @@ int main(Vector<String> args) { } } outvt.moveCursor(0, 0); - outvt << String(tmp, w*h) << "Press Ctrl+h for help"; + outvt << tmp.toString() << "Press Ctrl+h for help"; //Compute next generation for (int y = 0; y < h; y++) { @@ -82,12 +83,16 @@ int main(Vector<String> args) { u64int y = Rand::rand() * h / Rand::max(); cells[x * h + y] = true; } + } else if (kp.character == WChar("p")) { + outvt << " [PAUSED] press a key to resume"; + invt.getKeypress(); } else if (kp.character == WChar("h")) { outvt << "\n\n** Melon's demo Game Of Life Simulator help :\n"; outvt << " - ctrl+c : quit\n"; outvt << " - ctrl+h : show this\n"; + outvt << " - ctrl+p : pause\n"; outvt << " - ctrl+r : add some random cells\n"; - outvt << " - ctrl+R : add more cells, but not random\n\n"; + outvt << " - ctrl+R : add more cells, still random\n\n"; outvt << "Press any key to return to simultaor..."; invt.getKeypress(); } diff --git a/Source/Applications/PaperWork/main.cpp b/Source/Applications/PaperWork/main.cpp index 1a4c1c7..2fb40df 100644 --- a/Source/Applications/PaperWork/main.cpp +++ b/Source/Applications/PaperWork/main.cpp @@ -1,6 +1,8 @@ #include <Binding/Process.class.h> #include <String.class.h> +#define DEFAULT_SHELL "/Applications/Shell/Shell.app" + int main(Vector<String> args) { String act = "init"; if (args.size() == 2) { @@ -36,7 +38,10 @@ int main(Vector<String> args) { outvt << "Authentication failed.\n\n"; continue; } - Process p = Process::run("/Applications/Shell/Shell.app"); + outvt << "What shell to run [" << DEFAULT_SHELL << "]? "; + String sh = invt.readLine(); + if (sh == "") sh = DEFAULT_SHELL; + Process p = Process::run(sh); if (p.valid()) { p.setInVT(invt); p.setOutVT(outvt); diff --git a/Source/Kernel/Core/Log.ns.cpp b/Source/Kernel/Core/Log.ns.cpp index 1727024..d51aa55 100644 --- a/Source/Kernel/Core/Log.ns.cpp +++ b/Source/Kernel/Core/Log.ns.cpp @@ -1,4 +1,6 @@ #include "Log.ns.h" +#include <FileSystems/RamFS/RamFS.class.h> +#include <VTManager/SimpleVT.class.h> #include <VFS/VFS.ns.h> namespace Log { @@ -11,6 +13,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 + VFS::mount("/System/Logs:ramfs", kvt); + 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..c5af3e8 100644 --- a/Source/Kernel/Core/Sys.ns.cpp +++ b/Source/Kernel/Core/Sys.ns.cpp @@ -18,6 +18,10 @@ void outb (u16int port, u8int value) { asm volatile ("outb %1, %0" : : "dN" (port), "a" (value)); } +void outw (u16int port, u16int value) { + asm volatile ("outw %1, %0" : : "dN" (port), "a" (value)); +} + u8int inb (u16int port) { u8int ret; asm volatile ("inb %1, %0" : "=a" (ret) : "dN" (port)); @@ -83,7 +87,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..26f04e6 100644 --- a/Source/Kernel/Core/Sys.ns.h +++ b/Source/Kernel/Core/Sys.ns.h @@ -18,11 +18,15 @@ //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); + void outw(u16int port, u8int value); u8int inb(u16int port); u16int inw(u16int port); void dumpRegs(registers_t *regs, VirtualTerminal& vt); diff --git a/Source/Kernel/Core/kmain.wtf.cpp b/Source/Kernel/Core/kmain.wtf.cpp index 0486702..ad11eaf 100644 --- a/Source/Kernel/Core/kmain.wtf.cpp +++ b/Source/Kernel/Core/kmain.wtf.cpp @@ -7,6 +7,7 @@ #include <Devices/Display/VESADisplay.class.h> #include <Devices/Keyboard/PS2Keyboard.class.h> #include <Devices/Floppy/FloppyDrive.class.h> +#include <Devices/ATA/ATAController.class.h> #include <Devices/Timer.class.h> #include <DeviceManager/Disp.ns.h> #include <DeviceManager/Dev.ns.h> @@ -25,6 +26,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 +39,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 +87,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 +144,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 +168,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 @@ -179,17 +187,35 @@ void kmain(multiboot_info_t* mbd, u32int magic) { Kbd::setFocus(kvt); //Set focus to virtual terminal if (enableVESA) Dev::registerDevice(new VESADisplay()); FloppyController::detect(); + ATAController::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); + } + + { + TextFile mounts("/System/Configuration/Mount", FM_READ); + while (mounts.valid() && !mounts.eof()) { + String m = mounts.readLine(); + if (!m.empty() && m[0] != WChar("#")) VFS::mount(m, kvt, mbd); + } + } + + + //*************************************** 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 +225,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/ATA/ATAController.class.cpp b/Source/Kernel/Devices/ATA/ATAController.class.cpp new file mode 100644 index 0000000..d8073d0 --- /dev/null +++ b/Source/Kernel/Devices/ATA/ATAController.class.cpp @@ -0,0 +1,55 @@ +#include "ATADrive.class.h" + +#include <DeviceManager/Dev.ns.h> +#include <VFS/Part.ns.h> + +String ATAController::getClass() { + return "controller.ata"; +} + +String ATAController::getName() { + return String("ATA controller #") + String::number(m_number); +} + +void ATAController::detect() { + ATAController *c[2]; + c[0] = new ATAController(ATA_BUS1_BASE, 0); + c[1] = new ATAController(ATA_BUS2_BASE, 1); + Dev::registerDevice(c[0]); Dev::registerDevice(c[1]); + for (u32int d = 0; d < 2; d++) { + for (u32int r = 0; r < 2; r++) { + ATADrive* drv = c[d]->m_drives[r]; + if (drv != 0) { + Dev::registerDevice(drv); + Part::registerDevice(drv); + } + } + } +} + +ATAController::ATAController(u32int base, u8int number) : Mutex(MUTEX_TRUE) { + m_base = base; m_number = number; + m_drives[0] = NULL; m_drives[1] = NULL; + identify(false); //Identify master device + identify(true); //Identify slave device + unlock(); +} + +void ATAController::identify(bool slave) { + if (!locked()) return; + if (m_drives[(slave ? 1 : 0)] != NULL) return; + writeByte(ATA_PORT_DRIVE_SELECT, (slave ? 0xB0 : 0xA0)); + writeByte(ATA_PORT_COMMAND, ATA_CMD_IDENTIFY); + u8int ret = readByte(ATA_PORT_COMMAND); + if (ret == 0) return; //Drive does not exist + while ((ret & 0x88) != 0x08 and (ret & 1) != 1) { + ret = readByte(ATA_PORT_COMMAND); + } + if ((ret & 1) == 1) return; //Error while IDENTIFY + u16int data[256]; + for (u32int i = 0; i < 256; i++) data[i] = readWord(ATA_PORT_DATA); + u32int blocks = (data[61] << 16) | data[60]; + if (blocks != 0) { //Drive supports LBA28 + m_drives[(slave ? 1 : 0)] = new ATADrive(this, slave, blocks, data); + } +} diff --git a/Source/Kernel/Devices/ATA/ATAController.class.h b/Source/Kernel/Devices/ATA/ATAController.class.h new file mode 100644 index 0000000..89176c9 --- /dev/null +++ b/Source/Kernel/Devices/ATA/ATAController.class.h @@ -0,0 +1,48 @@ +#ifndef DEF_ATACONTROLLER_CLASS_H +#define DEF_ATACONTROLLER_CLASS_H + +#include <Devices/Device.proto.h> +#include <Mutex.class.h> + +#define ATA_BUS1_BASE 0x1F0 +#define ATA_BUS2_BASE 0x170 + +#define ATA_PORT_DATA 0 +#define ATA_PORT_FEATURES_ERROR 1 +#define ATA_PORT_SECT_COUNT 2 +#define ATA_PORT_PARTIAL1 3 +#define ATA_PORT_PARTIAL2 4 +#define ATA_PORT_PARTIAL3 5 +#define ATA_PORT_DRIVE_SELECT 6 +#define ATA_PORT_COMMAND 7 + +#define ATA_CMD_IDENTIFY 0xEC +#define ATA_CMD_READ 0x20 +#define ATA_CMD_WRITE 0x30 + +class ATADrive; + +class ATAController : public Device, public Mutex { + friend class ATADrive; + private: + ATAController(u32int base, u8int number); + + u32int m_base; + u8int m_number; + + ATADrive* m_drives[2]; + + void writeWord(u16int port, u16int word) { Sys::outw(m_base + port, word); } + void writeByte(u16int port, u8int byte) { Sys::outb(m_base + port, byte); } + u8int readByte(u16int port) { return Sys::inb(m_base + port); } + u16int readWord(u16int port) { return Sys::inw(m_base + port); } + + void identify(bool slave); //Identifies a drive and adds it to m_drives + + public: + static void detect(); + String getClass(); + String getName(); +}; + +#endif diff --git a/Source/Kernel/Devices/ATA/ATADrive.class.cpp b/Source/Kernel/Devices/ATA/ATADrive.class.cpp new file mode 100644 index 0000000..247e798 --- /dev/null +++ b/Source/Kernel/Devices/ATA/ATADrive.class.cpp @@ -0,0 +1,75 @@ +#include "ATADrive.class.h" + +String ATADrive::getClass() { + return "block.ata"; +} + +String ATADrive::getName() { + return String("ATA drive ") += String::number(m_ctrlr->m_number) += String(m_isSlave ? ".slave " : ".master ") + += String::number(m_blockCount / (1024 * 1024 / blockSize())) += "MB"; +} + +ATADrive::ATADrive(ATAController* ctrlr, bool isSlave, u32int blockCount, u16int* identifyData) { + m_ctrlr = ctrlr; + m_isSlave = isSlave; + m_blockCount = blockCount; + for (u32int i = 0; i < 256; i++) m_identifyData[i] = identifyData[i]; +} + +bool ATADrive::readOnly() { + return true; +} + +u64int ATADrive::blocks() { + return m_blockCount; +} + +void ATADrive::cmdCommon(u32int numblock, u32int count) { + m_ctrlr->writeByte(ATA_PORT_FEATURES_ERROR, 0); + m_ctrlr->writeByte(ATA_PORT_SECT_COUNT, count); + m_ctrlr->writeByte(ATA_PORT_PARTIAL1, numblock); + m_ctrlr->writeByte(ATA_PORT_PARTIAL2, numblock >> 8); + m_ctrlr->writeByte(ATA_PORT_PARTIAL3, numblock >> 16); + + m_ctrlr->writeByte(ATA_PORT_DRIVE_SELECT, 0xE0 | (m_isSlave ? 0x10 : 0) | ((numblock >> 24) & 0x0F)); +} + +bool ATADrive::readBlocks(u64int start, u32int count, u8int* data) { + if (start + count >= m_blockCount) return false; + + m_ctrlr->waitLock(); + cmdCommon(start, count); + m_ctrlr->writeByte(ATA_PORT_COMMAND, ATA_CMD_READ); + + while (!(m_ctrlr->readByte(ATA_PORT_COMMAND) & 0x08)); //Wait for the drive to be ready + + for (u32int idx = 0; idx < count * 256; idx++) { + u16int tmpword = m_ctrlr->readWord(ATA_PORT_DATA); + data[idx * 2] = (u8int)tmpword; + data[idx * 2 + 1] = (u8int)(tmpword >> 8); + } + m_ctrlr->unlock(); + return true; +} + +bool ATADrive::writeBlocks(u64int start, u32int count, u8int* data) { + if (start + count >= m_blockCount) return false; + if (readOnly()) return false; + + m_ctrlr->waitLock(); + cmdCommon(start, count); + m_ctrlr->writeByte(ATA_PORT_COMMAND, ATA_CMD_WRITE); + + while (!(m_ctrlr->readByte(ATA_PORT_COMMAND) & 0x08)); //Wait for the drive to be ready + + for (u32int idx = 0; idx < count * 256; idx++) { + u16int tmpword = (data[idx * 2]) | (data[idx * 2 + 1] << 8); + m_ctrlr->writeByte(ATA_PORT_DATA, tmpword); + } + m_ctrlr->unlock(); + return true; +} + +u32int ATADrive::blockSize() { + return 512; +} diff --git a/Source/Kernel/Devices/ATA/ATADrive.class.h b/Source/Kernel/Devices/ATA/ATADrive.class.h new file mode 100644 index 0000000..b6087bf --- /dev/null +++ b/Source/Kernel/Devices/ATA/ATADrive.class.h @@ -0,0 +1,30 @@ +#ifndef DEF_ATADRIVE_CLASS_H +#define DEF_ATADRIVE_CLASS_H + +#include "ATAController.class.h" +#include <Devices/BlockDevice.proto.h> + +class ATADrive : public BlockDevice { + friend class ATAController; + private: + ATADrive(ATAController* ctrlr, bool isSlave, u32int blockCount, u16int* identifyData); + + ATAController* m_ctrlr; + bool m_isSlave; + u32int m_blockCount; + u16int m_identifyData[256]; + + void cmdCommon(u32int numblock, u32int count); + + public: + String getClass(); + String getName(); + + bool readOnly(); + u64int blocks(); + bool readBlocks(u64int start, u32int count, u8int* data); + bool writeBlocks(u64int start, u32int count, u8int* data); + u32int blockSize(); +}; + +#endif 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..114622a --- /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(); + + 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); + + Partition* getPart() { return m_part; } +}; + +#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..0368e60 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; @@ -43,6 +43,8 @@ class RamFS : public FileSystem { FileNode* createFile(DirectoryNode* parent, String name); DirectoryNode* createDirectory(DirectoryNode* parent, String name); bool remove(DirectoryNode* parent, FSNode* node); + + Partition* getPart() { return 0; } }; #endif 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..660017a 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 \ @@ -76,6 +77,8 @@ Objects = Core/loader.wtf.o \ Devices/Keyboard/PS2Keyboard.class.o \ Devices/Floppy/FloppyController.class.o \ Devices/Floppy/FloppyDrive.class.o \ + Devices/ATA/ATAController.class.o \ + Devices/ATA/ATADrive.class.o \ Devices/Timer.class.o all: $(OutFile) 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..da5378b 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]->getIdentifier() << "\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..172c82c 100644 --- a/Source/Kernel/VFS/FileSystem.proto.h +++ b/Source/Kernel/VFS/FileSystem.proto.h @@ -5,17 +5,26 @@ 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*); + private: + String m_identifier; + 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; } @@ -34,6 +43,10 @@ class FileSystem { virtual FileNode* createFile(DirectoryNode* parent, String name) = 0; virtual DirectoryNode* createDirectory(DirectoryNode* parent, String name) = 0; virtual bool remove(DirectoryNode* parent, FSNode* node) = 0; + + virtual Partition* getPart() = 0; + void setIdentifier(String s) { m_identifier = s; } + String getIdentifier() { return m_identifier; } }; #endif diff --git a/Source/Kernel/VFS/Part.ns.cpp b/Source/Kernel/VFS/Part.ns.cpp index 6408dbd..415a150 100644 --- a/Source/Kernel/VFS/Part.ns.cpp +++ b/Source/Kernel/VFS/Part.ns.cpp @@ -1,5 +1,7 @@ #include "Part.ns.h" +#include <VTManager/SimpleVT.class.h> + namespace Part { Vector<BlockDevice*> devices; @@ -7,6 +9,21 @@ Vector<Partition*> partitions; void readPartitionTable(BlockDevice *dev) { //TODO : read partition table from device partitions.push(new Partition(dev, 0, 0, dev->blocks())); //Insert whole device as a partition + + u8int* mbr = (u8int*)Mem::alloc(dev->blockSize()); + if (!dev->readBlocks(0, 1, mbr)) return; + + mbr_entry_t* entries = (mbr_entry_t*)((u32int)mbr + 0x1BE); + + for (u32int i = 0; i < 4; i++) { + if ((entries[i].bootable == 0 or entries[i].bootable == 0x80) and entries[i].id != 0 + and entries[i].s_lba != 0 and entries[i].size != 0 + and entries[i].s_lba < dev->blocks() and entries[i].size < dev->blocks()) { + partitions.push(new Partition(dev, i + 1, entries[i].s_lba, entries[i].size)); + } + } + + Mem::free(mbr); } void registerDevice(BlockDevice *dev) { @@ -56,4 +73,32 @@ 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 && partitions[i]->getPartNumber() == idx) { + return partitions[i]; + } + } + 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..e6a358c 100644 --- a/Source/Kernel/VFS/Part.ns.h +++ b/Source/Kernel/VFS/Part.ns.h @@ -6,6 +6,19 @@ #include <VFS/Partition.class.h> namespace Part { + struct mbr_entry_t { + u8int bootable; /* 0 = no, 0x80 = bootable */ + u8int s_head; /* Starting head */ + u16int s_sector : 6; /* Starting sector */ + u16int s_cyl : 10; /* Starting cylinder */ + u8int id; /* System ID */ + u8int e_head; /* Ending head */ + u16int e_sector : 6; /* Ending sector */ + u16int e_cyl : 10; /* Ending cylinder */ + u32int s_lba; /* Starting sector (LBA value) */ + u32int size; /* Total sector number */ + } __attribute__ ((packed)); + extern Vector<BlockDevice*> devices; extern Vector<Partition*> partitions; @@ -13,6 +26,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..9da3461 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..cf68653 100644 --- a/Source/Kernel/VFS/VFS.ns.cpp +++ b/Source/Kernel/VFS/VFS.ns.cpp @@ -1,19 +1,130 @@ #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; + } + FileSystem* wat = RamFS::mount((u8int*)mods[fs[2].toInt()].mod_start, 1024 * 1024, root); + if (wat != NULL) { + wat->setIdentifier(str); + return true; + } + return false; + } else { + *vt << "Cannot mount kernel modules outside of kernel command line.\n"; + return false; + } + } else { + FileSystem* wat = RamFS::mount(1024 * 1024, root); + if (wat != NULL) { + wat->setIdentifier(str); + return true; + } + return false; + } + } 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; i < filesystems.size(); i++) { + if (filesystems[i]->getPart() == p) { + *vt << "Cannot mount " << str << " : partition already mounted.\n"; + return false; + } + } + for (u32int i = 0; fileSystems[i].cb != 0; i++) { + if (fs[4] == fileSystems[i].name or fs[4] == "") { + FileSystem* mounted = fileSystems[i].cb(p, root, (fs[5] == "rw")); + if (mounted != NULL) { + mounted->setIdentifier(str); + 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); diff --git a/Source/Library/Common/BasicString.class.cpp b/Source/Library/Common/BasicString.class.cpp index f3a6164..ddb4e2c 100644 --- a/Source/Library/Common/BasicString.class.cpp +++ b/Source/Library/Common/BasicString.class.cpp @@ -173,8 +173,10 @@ Vector< BasicString<T> > BasicString<T>::split(T sep) const { } template <typename T> -BasicString<T> BasicString<T>::substr(s32int start, u32int size) { +BasicString<T> BasicString<T>::substr(s32int start, s32int size) { + if (size == 0) return BasicString<T>(); if (start < 0) start = m_length - start; + if (size == -1) size = m_length - start; BasicString<T> ret; ret.m_string = new T[size + 1]; ret.m_length = size; diff --git a/Source/Library/Common/BasicString.class.h b/Source/Library/Common/BasicString.class.h index 21041e8..03d82c1 100644 --- a/Source/Library/Common/BasicString.class.h +++ b/Source/Library/Common/BasicString.class.h @@ -46,7 +46,7 @@ class BasicString { bool contains(const T& chr) const; Vector< BasicString<T> > split(T sep) const; - BasicString<T> substr(s32int start, u32int size); + BasicString<T> substr(s32int start, s32int size = -1); }; #include "BasicString.class.cpp" diff --git a/Source/Library/Common/ByteArray.class.cpp b/Source/Library/Common/ByteArray.class.cpp index 2a42702..95326f7 100644 --- a/Source/Library/Common/ByteArray.class.cpp +++ b/Source/Library/Common/ByteArray.class.cpp @@ -50,9 +50,9 @@ void ByteArray::resize(u32int size) { } String ByteArray::toString (u8int encoding) { - char* c = new char[m_length + 1]; + char* c = new char[m_length + 4]; memcpy((u8int*)c, m_string, m_length); - c[m_length] = 0; //Add NULL terminator + for (int i = 0; i < 4; i++) c[m_length + i] = 0; //Add NULL terminator String r(c, encoding); delete c; return r; diff --git a/Source/Library/Common/String.class.cpp b/Source/Library/Common/String.class.cpp index 63ff837..fe851bd 100644 --- a/Source/Library/Common/String.class.cpp +++ b/Source/Library/Common/String.class.cpp @@ -84,8 +84,8 @@ void String::affect (const char* string, u8int encoding) { return; } m_string = new WChar[m_length + 1]; - int i = 0, l = strlen(string), c = 0; - while (i < l) { + u32int i = 0, c = 0; + while (c < m_length) { i += m_string[c].affect(string + i, encoding); c++; } @@ -191,8 +191,10 @@ Vector<String> String::split(WChar c) const { return ret; } -String String::substr(s32int start, u32int size) { +String String::substr(s32int start, s32int size) { + if (size == 0) return String(); if (start < 0) start = m_length - start; + if (size == -1) size = m_length - start; String ret; ret.m_string = new WChar[size + 1]; ret.m_length = size; diff --git a/Source/Library/Common/String.class.h b/Source/Library/Common/String.class.h index 0d48ce6..b623fb2 100644 --- a/Source/Library/Common/String.class.h +++ b/Source/Library/Common/String.class.h @@ -43,7 +43,7 @@ class String : public BasicString<WChar> { Vector<String> split(WChar c) const; - String substr(s32int start, u32int size); + String substr(s32int start, s32int size = -1); }; #endif diff --git a/Source/Library/Common/WChar.class.cpp b/Source/Library/Common/WChar.class.cpp index f5bd5bc..312a5db 100644 --- a/Source/Library/Common/WChar.class.cpp +++ b/Source/Library/Common/WChar.class.cpp @@ -29,8 +29,10 @@ WChar::WChar(char c) { WChar::WChar(const char* c, u8int encoding) { if (encoding == UE_UTF8) affectUtf8(c); - if (encoding == UE_UTF16) affectUtf16(c); - if (encoding == UE_UTF32) affectUtf32(c); + if (encoding == UE_UTF16_LE) affectUtf16le(c); + if (encoding == UE_UTF16_BE) affectUtf16be(c); + if (encoding == UE_UTF32_LE) affectUtf32le(c); + if (encoding == UE_UTF32_BE) affectUtf32be(c); } u32int WChar::ucharLen(const char* c, u8int encoding) { @@ -40,18 +42,21 @@ u32int WChar::ucharLen(const char* c, u8int encoding) { else if ((c[0] & 0xF0) == 0xE0) return 3; else if ((c[0] & 0xF8) == 0xF0) return 4; else return 1; - } else if (encoding == UE_UTF16) { + } else if (encoding == UE_UTF16_BE) { if ((c[0] & 0xFC) == 0xD8 and (c[2] & 0xFC) == 0xDC) return 4; else return 2; - } else if (encoding == UE_UTF32) { + } else if (encoding == UE_UTF16_LE) { + if ((c[1] & 0xFC) == 0xD8 and (c[3] & 0xFC) == 0xDC) return 4; + else return 2; + } else if (encoding == UE_UTF32_LE or encoding == UE_UTF16_BE) { return 4; } return 1; } u32int WChar::utfLen(const char* c, u8int encoding) { - int i = 0, l = strlen(c), co = 0; - while (i < l) { + int i = 0, co = 0; + while (WChar(c + i, encoding) != 0) { i += ucharLen(c + i, encoding); co++; } @@ -90,7 +95,7 @@ u32int WChar::affectUtf8(const char* c) { //Returns the number of bytes for the return 1; } -u32int WChar::affectUtf16(const char* c) { +u32int WChar::affectUtf16be(const char* c) { if ((c[0] & 0xFC) == 0xD8 and // 11111100b, 11011000b (c[2] & 0xFC) == 0xDC) { // 11111100b, 11011100b u32int w = ((c[0] & 0x03) << 2) | ((c[1] & 0xC0) >> 6); @@ -108,13 +113,38 @@ u32int WChar::affectUtf16(const char* c) { } } -u32int WChar::affectUtf32(const char* c) { +u32int WChar::affectUtf16le(const char* c) { + if ((c[1] & 0xFC) == 0xD8 and // 11111100b, 11011000b + (c[3] & 0xFC) == 0xDC) { // 11111100b, 11011100b + u32int w = ((c[1] & 0x03) << 2) | ((c[0] & 0xC0) >> 6); + u32int x = (c[0] & 0x3F); + u32int y = ((c[3] & 0x03) << 8) | (c[3]); + value = ((w + 1) << 16) | (x << 10) | y; + if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed + if (value >= 0xFFFE and value <= 0xFFFF) value = 0; + return 4; + } else { + value = (c[1] << 8) | (c[0]); + if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed + if (value >= 0xFFFE and value <= 0xFFFF) value = 0; + return 2; + } +} + +u32int WChar::affectUtf32be(const char* c) { value = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed if (value >= 0xFFFE and value <= 0xFFFF) value = 0; return 4; } +u32int WChar::affectUtf32le(const char* c) { + value = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0]; + if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed + if (value >= 0xFFFE and value <= 0xFFFF) value = 0; + return 4; +} + u8int WChar::toAscii() { if (value < 128) return (char)value; for (int i = 0; i < 128; i++) { @@ -144,9 +174,9 @@ uchar_repr_t WChar::toUtf8() { return r; } -//TODO : code WChar::toUtf16 +//TODO : code WChar::toUtf16(be|le) -uchar_repr_t WChar::toUtf32() { +uchar_repr_t WChar::toUtf32be() { uchar_repr_t r; r.c[0] = (value >> 24) & 0xFF; r.c[1] = (value >> 16) & 0xFF; @@ -154,3 +184,12 @@ uchar_repr_t WChar::toUtf32() { r.c[3] = value & 0xFF; return r; } + +uchar_repr_t WChar::toUtf32le() { + uchar_repr_t r; + r.c[3] = (value >> 24) & 0xFF; + r.c[2] = (value >> 16) & 0xFF; + r.c[1] = (value >> 8) & 0xFF; + r.c[0] = value & 0xFF; + return r; +} diff --git a/Source/Library/Common/WChar.class.h b/Source/Library/Common/WChar.class.h index 5d6d26b..afaeb44 100644 --- a/Source/Library/Common/WChar.class.h +++ b/Source/Library/Common/WChar.class.h @@ -9,8 +9,10 @@ enum { UE_UTF8, - UE_UTF16, - UE_UTF32, + UE_UTF16_LE, + UE_UTF16_BE, + UE_UTF32_LE, + UE_UTF32_BE, }; union uchar_repr_t { @@ -31,13 +33,17 @@ struct WChar { void affectAscii(char c); u32int affectUtf8(const char* c); - u32int affectUtf16(const char* c); - u32int affectUtf32(const char* c); + u32int affectUtf16le(const char* c); + u32int affectUtf16be(const char* c); + u32int affectUtf32le(const char* c); + u32int affectUtf32be(const char* c); u32int affect(const char* c, u8int encoding = UE_UTF8) { if (encoding == UE_UTF8) return affectUtf8(c); - if (encoding == UE_UTF16) return affectUtf16(c); - if (encoding == UE_UTF32) return affectUtf32(c); + if (encoding == UE_UTF16_LE) return affectUtf16le(c); + if (encoding == UE_UTF16_BE) return affectUtf16be(c); + if (encoding == UE_UTF32_LE) return affectUtf32le(c); + if (encoding == UE_UTF32_BE) return affectUtf32be(c); affectAscii(c[0]); //Default case :/ return 1; } @@ -45,13 +51,17 @@ struct WChar { u8int toAscii(); uchar_repr_t toUtf8(); - uchar_repr_t toUtf16(); - uchar_repr_t toUtf32(); + uchar_repr_t toUtf16le(); + uchar_repr_t toUtf16be(); + uchar_repr_t toUtf32le(); + uchar_repr_t toUtf32be(); uchar_repr_t encode(u8int encoding = UE_UTF8) { if (encoding == UE_UTF8) return toUtf8(); - //if (encoding == UE_UTF16) return toUtf16(); - if (encoding == UE_UTF32) return toUtf32(); + //if (encoding == UE_UTF16_LE) return toUtf16le(); + //if (encoding == UE_UTF16_BE) return toUtf16be(); + if (encoding == UE_UTF32_LE) return toUtf32le(); + if (encoding == UE_UTF32_BE) return toUtf32be(); uchar_repr_t x; x.c[0] = toAscii(); return x; |