CHECKP: semi-stable vfs

This commit is contained in:
boreddevnl 2026-04-11 23:08:33 +02:00
parent 5933483009
commit 38ed0b5ffa
6 changed files with 704 additions and 456 deletions

BIN
disk.img

Binary file not shown.

View file

@ -9,8 +9,11 @@
#include "ahci.h" #include "ahci.h"
#include "../fs/vfs.h" #include "../fs/vfs.h"
#include "../fs/fat32.h" #include "../fs/fat32.h"
#include "../sys/spinlock.h"
#include <stddef.h> #include <stddef.h>
static spinlock_t ide_lock = SPINLOCK_INIT;
static Disk *disks[MAX_DISKS]; static Disk *disks[MAX_DISKS];
static int disk_count = 0; static int disk_count = 0;
static int next_drive_letter_idx = 0; // For backward compat static int next_drive_letter_idx = 0; // For backward compat
@ -75,12 +78,17 @@ typedef struct {
// === ATA PIO Driver === // === ATA PIO Driver ===
static void ata_wait_bsy(uint16_t port_base) { static int ata_wait_bsy(uint16_t port_base) {
while (inb(port_base + ATA_REG_STATUS) & ATA_SR_BSY); int timeout = 10000000;
while ((inb(port_base + ATA_REG_STATUS) & ATA_SR_BSY) && --timeout > 0);
return timeout <= 0 ? -1 : 0;
} }
static void ata_wait_drq(uint16_t port_base) { static int ata_wait_drq(uint16_t port_base) {
while (!(inb(port_base + ATA_REG_STATUS) & ATA_SR_DRQ)); int timeout = 10000000;
while (!(inb(port_base + ATA_REG_STATUS) & (ATA_SR_DRQ | ATA_SR_ERR)) && --timeout > 0);
if (timeout <= 0 || (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR)) return -1;
return 0;
} }
static int ata_identify(uint16_t port_base, bool slave) { static int ata_identify(uint16_t port_base, bool slave) {
@ -104,7 +112,7 @@ static int ata_identify(uint16_t port_base, bool slave) {
if (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR) return 0; if (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR) return 0;
while (!(inb(port_base + ATA_REG_STATUS) & (ATA_SR_DRQ | ATA_SR_ERR))); if (ata_wait_drq(port_base) != 0) return 0;
if (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR) return 0; if (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR) return 0;
@ -132,7 +140,12 @@ static int ata_read_sector(Disk *disk, uint32_t lba, uint8_t *buffer) {
slave = data->slave; slave = data->slave;
} }
ata_wait_bsy(port_base); uint64_t flags = spinlock_acquire_irqsave(&ide_lock);
if (ata_wait_bsy(port_base) != 0) {
spinlock_release_irqrestore(&ide_lock, flags);
return -1;
}
outb(port_base + ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | ((lba >> 24) & 0x0F)); outb(port_base + ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | ((lba >> 24) & 0x0F));
outb(port_base + ATA_REG_FEATURES, 0x00); outb(port_base + ATA_REG_FEATURES, 0x00);
@ -142,14 +155,21 @@ static int ata_read_sector(Disk *disk, uint32_t lba, uint8_t *buffer) {
outb(port_base + ATA_REG_LBA2, (uint8_t)(lba >> 16)); outb(port_base + ATA_REG_LBA2, (uint8_t)(lba >> 16));
outb(port_base + ATA_REG_COMMAND, ATA_CMD_READ_PIO); outb(port_base + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
ata_wait_bsy(port_base); if (ata_wait_bsy(port_base) != 0) {
ata_wait_drq(port_base); spinlock_release_irqrestore(&ide_lock, flags);
return -1;
}
if (ata_wait_drq(port_base) != 0) {
spinlock_release_irqrestore(&ide_lock, flags);
return -1;
}
uint16_t *ptr = (uint16_t*)buffer; uint16_t *ptr = (uint16_t*)buffer;
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
ptr[i] = inw(port_base + ATA_REG_DATA); ptr[i] = inw(port_base + ATA_REG_DATA);
} }
spinlock_release_irqrestore(&ide_lock, flags);
return 0; return 0;
} }
@ -166,7 +186,12 @@ static int ata_write_sector(Disk *disk, uint32_t lba, const uint8_t *buffer) {
slave = data->slave; slave = data->slave;
} }
ata_wait_bsy(port_base); uint64_t flags = spinlock_acquire_irqsave(&ide_lock);
if (ata_wait_bsy(port_base) != 0) {
spinlock_release_irqrestore(&ide_lock, flags);
return -1;
}
outb(port_base + ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | ((lba >> 24) & 0x0F)); outb(port_base + ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | ((lba >> 24) & 0x0F));
outb(port_base + ATA_REG_FEATURES, 0x00); outb(port_base + ATA_REG_FEATURES, 0x00);
@ -176,8 +201,14 @@ static int ata_write_sector(Disk *disk, uint32_t lba, const uint8_t *buffer) {
outb(port_base + ATA_REG_LBA2, (uint8_t)(lba >> 16)); outb(port_base + ATA_REG_LBA2, (uint8_t)(lba >> 16));
outb(port_base + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); outb(port_base + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
ata_wait_bsy(port_base); if (ata_wait_bsy(port_base) != 0) {
ata_wait_drq(port_base); spinlock_release_irqrestore(&ide_lock, flags);
return -1;
}
if (ata_wait_drq(port_base) != 0) {
spinlock_release_irqrestore(&ide_lock, flags);
return -1;
}
const uint16_t *ptr = (const uint16_t*)buffer; const uint16_t *ptr = (const uint16_t*)buffer;
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
@ -185,8 +216,12 @@ static int ata_write_sector(Disk *disk, uint32_t lba, const uint8_t *buffer) {
} }
outb(port_base + ATA_REG_COMMAND, 0xE7); // Cache Flush outb(port_base + ATA_REG_COMMAND, 0xE7); // Cache Flush
ata_wait_bsy(port_base); if (ata_wait_bsy(port_base) != 0) {
spinlock_release_irqrestore(&ide_lock, flags);
return -1;
}
spinlock_release_irqrestore(&ide_lock, flags);
return 0; return 0;
} }

File diff suppressed because it is too large Load diff

View file

@ -101,6 +101,8 @@ typedef struct {
bool valid; // Is this handle valid? bool valid; // Is this handle valid?
uint32_t dir_sector; // Sector containing the directory entry uint32_t dir_sector; // Sector containing the directory entry
uint32_t dir_offset; // Offset within that sector uint32_t dir_offset; // Offset within that sector
bool is_directory; // Is this a directory?
uint8_t attributes; // File attributes
void *volume; // Pointer to owning FAT32_Volume (or NULL for ramfs) void *volume; // Pointer to owning FAT32_Volume (or NULL for ramfs)
} FAT32_FileHandle; } FAT32_FileHandle;

View file

@ -339,12 +339,14 @@ void vfs_close(vfs_file_t *file) {
int vfs_read(vfs_file_t *file, void *buf, int size) { int vfs_read(vfs_file_t *file, void *buf, int size) {
if (!file || !file->valid || !file->mount) return -1; if (!file || !file->valid || !file->mount) return -1;
if (!file->mount->ops->read) return -1; if (!file->mount->ops->read) return -1;
return file->mount->ops->read(file->mount->fs_private, file->fs_handle, buf, size); return file->mount->ops->read(file->mount->fs_private, file->fs_handle, buf, size);
} }
int vfs_write(vfs_file_t *file, const void *buf, int size) { int vfs_write(vfs_file_t *file, const void *buf, int size) {
if (!file || !file->valid || !file->mount) return -1; if (!file || !file->valid || !file->mount) return -1;
if (!file->mount->ops->write) return -1; if (!file->mount->ops->write) return -1;
return file->mount->ops->write(file->mount->fs_private, file->fs_handle, buf, size); return file->mount->ops->write(file->mount->fs_private, file->fs_handle, buf, size);
} }
@ -372,6 +374,7 @@ uint32_t vfs_file_size(vfs_file_t *file) {
int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) { int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) {
if (!path || !entries) return -1; if (!path || !entries) return -1;
char normalized[VFS_MAX_PATH]; char normalized[VFS_MAX_PATH];
vfs_normalize_path(path, normalized); vfs_normalize_path(path, normalized);
@ -483,10 +486,15 @@ bool vfs_mkdir(const char *path) {
const char *rel_path = NULL; const char *rel_path = NULL;
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path); vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
// If it's in /dev/, check if it's within a mounted volume deeper than the device node
if (vfs_starts_with(normalized, "/dev/")) {
if (!mount || !rel_path || rel_path[0] == '\0') {
return false; // Protect raw device nodes
}
}
if (!mount || !mount->ops->mkdir) return false; if (!mount || !mount->ops->mkdir) return false;
if (!rel_path || rel_path[0] == '\0') return false;
return mount->ops->mkdir(mount->fs_private, rel_path); return mount->ops->mkdir(mount->fs_private, rel_path);
} }
@ -496,17 +504,21 @@ bool vfs_rmdir(const char *path) {
char normalized[VFS_MAX_PATH]; char normalized[VFS_MAX_PATH];
vfs_normalize_path(path, normalized); vfs_normalize_path(path, normalized);
// Protect root and virtual directories // Protect root and virtual /dev directory itself
if (normalized[0] == '/' && normalized[1] == '\0') return false; if (normalized[0] == '/' && normalized[1] == '\0') return false;
if (vfs_strcmp(normalized, "/dev") == 0) return false; if (vfs_strcmp(normalized, "/dev") == 0) return false;
if (vfs_starts_with(normalized, "/dev/")) return false;
const char *rel_path = NULL; const char *rel_path = NULL;
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path); vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
// If it's in /dev/, allow only if it's inside a mount beyond the device node
if (vfs_starts_with(normalized, "/dev/")) {
if (!mount || !rel_path || rel_path[0] == '\0') {
return false; // Protect raw device nodes
}
}
if (!mount || !mount->ops->rmdir) return false; if (!mount || !mount->ops->rmdir) return false;
if (!rel_path || rel_path[0] == '\0') return false;
return mount->ops->rmdir(mount->fs_private, rel_path); return mount->ops->rmdir(mount->fs_private, rel_path);
} }
@ -516,17 +528,21 @@ bool vfs_delete(const char *path) {
char normalized[VFS_MAX_PATH]; char normalized[VFS_MAX_PATH];
vfs_normalize_path(path, normalized); vfs_normalize_path(path, normalized);
// Protect root and virtual directories // Protect root and virtual /dev directory itself
if (normalized[0] == '/' && normalized[1] == '\0') return false; if (normalized[0] == '/' && normalized[1] == '\0') return false;
if (vfs_strcmp(normalized, "/dev") == 0) return false; if (vfs_strcmp(normalized, "/dev") == 0) return false;
if (vfs_starts_with(normalized, "/dev/")) return false;
const char *rel_path = NULL; const char *rel_path = NULL;
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path); vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
// If it's in /dev/, allow only if it's inside a mount beyond the device node
if (vfs_starts_with(normalized, "/dev/")) {
if (!mount || !rel_path || rel_path[0] == '\0') {
return false; // Protect raw device nodes
}
}
if (!mount || !mount->ops->unlink) return false; if (!mount || !mount->ops->unlink) return false;
if (!rel_path || rel_path[0] == '\0') return false;
return mount->ops->unlink(mount->fs_private, rel_path); return mount->ops->unlink(mount->fs_private, rel_path);
} }

View file

@ -709,7 +709,13 @@ static void explorer_load_directory(Window *win, const char *path) {
if (!entries) return; if (!entries) return;
int count = vfs_list_directory(path, entries, capacity); int count = vfs_list_directory(path, entries, capacity);
// Trace string to see if we reached here
extern void serial_write(const char*); extern void serial_write_num(uint32_t);
serial_write("[EXPLORER] load_directory: "); serial_write(path); serial_write(" | loop start. count: "); serial_write_num(count); serial_write("\n");
while (count == capacity) { while (count == capacity) {
serial_write("[EXPLORER] Doubling capacity to: "); serial_write_num(capacity * 2); serial_write("\n");
capacity *= 2; capacity *= 2;
vfs_dirent_t *new_entries = (vfs_dirent_t*)krealloc(entries, capacity * sizeof(vfs_dirent_t)); vfs_dirent_t *new_entries = (vfs_dirent_t*)krealloc(entries, capacity * sizeof(vfs_dirent_t));
if (!new_entries) { kfree(entries); return; } if (!new_entries) { kfree(entries); return; }
@ -717,6 +723,8 @@ static void explorer_load_directory(Window *win, const char *path) {
count = vfs_list_directory(path, entries, capacity); count = vfs_list_directory(path, entries, capacity);
} }
serial_write("[EXPLORER] load_directory loop complete.\n");
if (state->items_capacity < count) { if (state->items_capacity < count) {
int new_cap = count < EXPLORER_INITIAL_CAPACITY ? EXPLORER_INITIAL_CAPACITY : count; int new_cap = count < EXPLORER_INITIAL_CAPACITY ? EXPLORER_INITIAL_CAPACITY : count;
ExplorerItem *new_items = (ExplorerItem*)krealloc(state->items, new_cap * sizeof(ExplorerItem)); ExplorerItem *new_items = (ExplorerItem*)krealloc(state->items, new_cap * sizeof(ExplorerItem));