diff --git a/source/includes/ahci.h b/source/includes/ahci.h index 337e311..eb9dbcd 100755 --- a/source/includes/ahci.h +++ b/source/includes/ahci.h @@ -182,7 +182,8 @@ typedef enum { FS_UDF, // OS / Custom - FS_PROC + FS_PROC, + FS_DEV } partition_fs_type_t; diff --git a/source/includes/filesystems/layers/dev.h b/source/includes/filesystems/layers/dev.h new file mode 100644 index 0000000..5e4e4b4 --- /dev/null +++ b/source/includes/filesystems/layers/dev.h @@ -0,0 +1,22 @@ +/** + * @file dev.h + * @author Pradosh (pradoshgame@gmail.com) + * @brief The dev folder to handle by the VFS. + * @version 0.1 + * @date 2026-04-04 + */ + +#ifndef DEV_H +#define DEV_H + +#include +#include + +void devfs_init(void); +int devfs_open(vfs_file_t* file); +int devfs_read(vfs_file_t* file, uint8_t* buf, uint32_t size); +int devfs_write(vfs_file_t* file, const uint8_t* buf, uint32_t size); +void devfs_close(vfs_file_t* file); +int devfs_ls(void); + +#endif diff --git a/source/includes/filesystems/layers/proc.h b/source/includes/filesystems/layers/proc.h index 33f3afa..cbf313b 100644 --- a/source/includes/filesystems/layers/proc.h +++ b/source/includes/filesystems/layers/proc.h @@ -45,5 +45,6 @@ int procfs_open(vfs_file_t* file); int procfs_read(vfs_file_t* file, uint8_t* buf, uint32_t size); int procfs_write(vfs_file_t* file, const uint8_t* buf, uint32_t size); void procfs_close(vfs_file_t* file); +int procfs_ls(void); #endif diff --git a/source/kernel/C/filesystems/layers/dev.c b/source/kernel/C/filesystems/layers/dev.c new file mode 100644 index 0000000..736acf0 --- /dev/null +++ b/source/kernel/C/filesystems/layers/dev.c @@ -0,0 +1,227 @@ +/** + * @file dev.c + * @author Pradosh (pradoshgame@gmail.com) + * @brief The dev folder to handle by the VFS. + * @version 0.1 + * @date 2026-04-04 + */ + +#include +#include +#include +#include +#include +#include + +static uint64_t devfs_rng_state = 0x9E3779B97F4A7C15ULL; + +static int devfs_disk_id_from_name(const char* name) +{ + if (!name || !*name) + return -1; + + for (int i = 0; i < block_device_count; i++) { + block_device_info_t* dev = &block_devices[i]; + if (!dev->present) + continue; + + if (dev->type != BLOCK_DEVICE_AHCI && dev->type != BLOCK_DEVICE_NVME) + continue; + + if (strcmp(dev->name, name) == 0) + return i; + } + + return -1; +} + +static bool devfs_is_block_node(const char* name) +{ + int id = devfs_disk_id_from_name(name); + return id >= 0; +} + +void devfs_init(void) { + devfs_rng_state ^= rdtsc64(); +} + +static uint8_t devfs_next_rand_u8(void) +{ + devfs_rng_state ^= devfs_rng_state << 13; + devfs_rng_state ^= devfs_rng_state >> 7; + devfs_rng_state ^= devfs_rng_state << 17; + return (uint8_t)(devfs_rng_state & 0xFF); +} + +int devfs_open(vfs_file_t* file) +{ + if (!file || !file->rel_path) + return -1; + + if (file->rel_path[0] == '\0') { + file->pos = 0; + return 0; + } + + if (strcmp(file->rel_path, "null") == 0 || + strcmp(file->rel_path, "zero") == 0 || + strcmp(file->rel_path, "random") == 0 || + strcmp(file->rel_path, "urandom") == 0) { + file->pos = 0; + return 0; + } + + if (devfs_is_block_node(file->rel_path)) { + file->pos = 0; + return 0; + } + + return -1; +} + +int devfs_read(vfs_file_t* file, uint8_t* buf, uint32_t size) +{ + if (!file || !buf) + return -1; + + if (strcmp(file->rel_path, "null") == 0) + return 0; + + if (strcmp(file->rel_path, "zero") == 0) { + memset(buf, 0, size); + file->pos += size; + return (int)size; + } + + if (strcmp(file->rel_path, "random") == 0 || strcmp(file->rel_path, "urandom") == 0) { + for (uint32_t i = 0; i < size; i++) + buf[i] = devfs_next_rand_u8(); + file->pos += size; + return (int)size; + } + + int disk_id = devfs_disk_id_from_name(file->rel_path); + if (disk_id < 0) + return -1; + + block_device_info_t* dev = block_get_device(disk_id); + if (!dev || dev->sector_size == 0) + return -1; + + uint8_t* secbuf = kmalloc(dev->sector_size); + if (!secbuf) + return -1; + + uint32_t done = 0; + while (done < size) { + uint64_t abs = (uint64_t)file->pos + done; + uint64_t lba = abs / dev->sector_size; + uint32_t off = abs % dev->sector_size; + uint32_t chunk = dev->sector_size - off; + + if (chunk > (size - done)) + chunk = size - done; + + if (block_read_sector(disk_id, lba, secbuf, 1) != 0) { + kfree(secbuf); + return done > 0 ? (int)done : -1; + } + + memcpy(buf + done, secbuf + off, chunk); + done += chunk; + } + + kfree(secbuf); + file->pos += done; + return (int)done; +} + +int devfs_write(vfs_file_t* file, const uint8_t* buf, uint32_t size) +{ + if (!file || !buf) + return -1; + + if (strcmp(file->rel_path, "null") == 0) { + file->pos += size; + return (int)size; + } + + if (strcmp(file->rel_path, "zero") == 0) + return -1; + + if (strcmp(file->rel_path, "random") == 0 || strcmp(file->rel_path, "urandom") == 0) { + file->pos += size; + return (int)size; + } + + int disk_id = devfs_disk_id_from_name(file->rel_path); + if (disk_id < 0) + return -1; + + block_device_info_t* dev = block_get_device(disk_id); + if (!dev || dev->sector_size == 0) + return -1; + + uint8_t* secbuf = kmalloc(dev->sector_size); + if (!secbuf) + return -1; + + uint32_t done = 0; + while (done < size) { + uint64_t abs = (uint64_t)file->pos + done; + uint64_t lba = abs / dev->sector_size; + uint32_t off = abs % dev->sector_size; + uint32_t chunk = dev->sector_size - off; + + if (chunk > (size - done)) + chunk = size - done; + + if (off != 0 || chunk != dev->sector_size) { + if (block_read_sector(disk_id, lba, secbuf, 1) != 0) { + kfree(secbuf); + return done > 0 ? (int)done : -1; + } + } else { + memset(secbuf, 0, dev->sector_size); + } + + memcpy(secbuf + off, buf + done, chunk); + + if (block_write_sector(disk_id, lba, secbuf, 1) != 0) { + kfree(secbuf); + return done > 0 ? (int)done : -1; + } + + done += chunk; + } + + kfree(secbuf); + file->pos += done; + return (int)done; +} + +void devfs_close(vfs_file_t* file) +{ + (void)file; +} + +int devfs_ls(void) +{ + printfnoln(blue_color "null " reset_color); + printfnoln(blue_color "zero " reset_color); + printfnoln(blue_color "random " reset_color); + printfnoln(blue_color "urandom " reset_color); + + for (int i = 0; i < block_device_count; i++) { + block_device_info_t* dev = &block_devices[i]; + if (!dev->present) + continue; + + if (dev->type != BLOCK_DEVICE_AHCI && dev->type != BLOCK_DEVICE_NVME) + continue; + + printfnoln(blue_color "%s " reset_color, dev->name); + } + + return 0; +} diff --git a/source/kernel/C/filesystems/vfs.c b/source/kernel/C/filesystems/vfs.c index 96f9265..a808e9a 100644 --- a/source/kernel/C/filesystems/vfs.c +++ b/source/kernel/C/filesystems/vfs.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -143,6 +145,8 @@ int vfs_read(vfs_file_t* file, uint8_t* buf, uint32_t size) switch(file->mnt->type){ case FS_PROC: return procfs_read(file, buf, size); + case FS_DEV: + return devfs_read(file, buf, size); case FS_FAT16: return fat16_read(&file->f.fat16, buf, size); case FS_FAT32: @@ -173,6 +177,8 @@ int vfs_write(vfs_file_t* file, const uint8_t* buf, uint32_t size) switch(file->mnt->type){ case FS_PROC: return -10; // not implemented + case FS_DEV: + return devfs_write(file, buf, size); case FS_FAT16: return fat16_write(&file->f.fat16, buf, size); case FS_FAT32: @@ -198,6 +204,8 @@ void vfs_close(vfs_file_t* file) { switch(file->mnt->type){ case FS_PROC: return; // not implemented + case FS_DEV: + return devfs_close(file); case FS_FAT16: return fat16_close(&file->f.fat16); case FS_FAT32: @@ -244,6 +252,12 @@ int vfs_ls(const char* path) entries = true; } } + if(res.mnt->type == FS_DEV) { + if (res.rel_path[0] == '\0') { + devfs_ls(); + entries = true; + } + } if (res.mnt->type == FS_FAT16) { fat16_fs_t* fs = (fat16_fs_t*)res.mnt->fs; @@ -348,6 +362,17 @@ int vfs_open(const char* path, int flags, vfs_file_t* out) return 0; } + if (res.mnt->type == FS_DEV) { + strncpy(out->rel_path, res.rel_path, sizeof(out->rel_path)); + out->mnt = res.mnt; + out->flags = flags; + + if (devfs_open(out) != 0) + return -1; + + return 0; + } + if (res.mnt->type == FS_FAT16) { fat16_fs_t* fs = (fat16_fs_t*)res.mnt->fs; int ret; @@ -569,6 +594,16 @@ int vfs_cd(const char* path) return 0; } + if (res.mnt->type == FS_DEV) { + if (*res.rel_path) + return -4; + + vfs_cwd_cluster = 0; + strncpy(vfs_cwd, norm, sizeof(vfs_cwd)); + vfs_cwd[sizeof(vfs_cwd) - 1] = 0; + return 0; + } + if (res.mnt->type == FS_FAT32) { fat32_fs_t* fs = (fat32_fs_t*)res.mnt->fs; uint32_t new_cluster = fs->root_cluster; diff --git a/source/kernel/C/shell/commands/lsblk.c b/source/kernel/C/shell/commands/lsblk.c index 2313395..1f00edf 100644 --- a/source/kernel/C/shell/commands/lsblk.c +++ b/source/kernel/C/shell/commands/lsblk.c @@ -29,6 +29,7 @@ static const char* fs_name(partition_fs_type_t fs) case FS_FAT32: return "fat32"; case FS_ISO9660: return "iso9660"; case FS_PROC: return "proc"; + case FS_DEV: return "dev"; default: return "unknown"; } } @@ -58,6 +59,7 @@ static const char* ro_flag_for_filesystem(partition_fs_type_t fs) switch (fs) { case FS_ISO9660: case FS_PROC: + case FS_DEV: return "1"; default: return "0"; diff --git a/source/kernel/C/shell/commands/mount.c b/source/kernel/C/shell/commands/mount.c index fe781e5..7473213 100644 --- a/source/kernel/C/shell/commands/mount.c +++ b/source/kernel/C/shell/commands/mount.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include const char* fs_type_to_string(int fs) @@ -22,6 +24,7 @@ const char* fs_type_to_string(int fs) case FS_FAT16: return "FAT16"; case FS_FAT32: return "FAT32"; case FS_PROC: return "PROCFS"; + case FS_DEV: return "DEVFS"; case FS_ISO9660:return "ISO9660"; default: return "UNKNOWN"; } @@ -68,6 +71,24 @@ int cmd_mount(int argc, char** argv) return 0; } + if(strcmp(device, "dev") == 0){ + mount_entry_t* new_mount = add_mount(mount_point, device, FS_DEV, NULL); + if (!new_mount) + return 1; + + devfs_init(); + + if(strcmp(mount_point, "/dev") != 0) + printf("mount: warning mounting 'dev' on non-standard path."); + + printf("mount: mounted " red_color "%s" reset_color " (%s) at '%s'", + device, + fs_type_to_string(FS_DEV), + mount_point); + + return 0; + } + general_partition_t* partition = search_general_partition(device); if (!partition) { diff --git a/source/kernel/C/shell/commands/umount.c b/source/kernel/C/shell/commands/umount.c index 64d7497..b2635b1 100644 --- a/source/kernel/C/shell/commands/umount.c +++ b/source/kernel/C/shell/commands/umount.c @@ -45,6 +45,8 @@ int cmd_umount(int argc, char** argv) case FS_PROC: // procfs_shutdown(); /* or procfs_unmount() */ break; + case FS_DEV: + break; default: printf("umount: unsupported filesystem"); @@ -58,4 +60,4 @@ int cmd_umount(int argc, char** argv) printf("umount: %s unmounted", mount_point); return 0; -} \ No newline at end of file +} diff --git a/source/kernel/C/stream.c b/source/kernel/C/stream.c index 733488a..6878549 100644 --- a/source/kernel/C/stream.c +++ b/source/kernel/C/stream.c @@ -294,6 +294,7 @@ uint32_t fd_file_size(int fd) case FS_ISO9660: return file->f.iso9660.entry.size; case FS_PROC: + case FS_DEV: default: return 0; } @@ -313,6 +314,7 @@ uint32_t* fd_pos_ptr(int fd) case FS_ISO9660: return &file->f.iso9660.pos; case FS_PROC: + case FS_DEV: return &file->pos; default: return NULL; diff --git a/source/kernel/C/syscalls.c b/source/kernel/C/syscalls.c index f87860f..f074b45 100644 --- a/source/kernel/C/syscalls.c +++ b/source/kernel/C/syscalls.c @@ -21,6 +21,7 @@ // Entire filesystems present in the OS. #include #include +#include #include #include #include @@ -201,6 +202,24 @@ static bool fill_vfs_stat_for_path_at(int dirfd, const char* path, vfs_stat_info return true; } + if (res.mnt->type == FS_DEV) { + if (res.rel_path[0] == '\0') { + info->is_dir = true; + info->mode = LINUX_S_IFDIR | 0555; + return true; + } + + vfs_file_t devf = {0}; + snprintf(devf.rel_path, sizeof(devf.rel_path), "%s", res.rel_path); + devf.mnt = res.mnt; + if (devfs_open(&devf) != 0) + return false; + info->is_dir = false; + info->mode = LINUX_S_IFCHR | 0666; + info->size = 0; + return true; + } + if (res.rel_path[0] == '\0') { info->is_dir = true; info->mode = LINUX_S_IFDIR | 0755; @@ -255,6 +274,7 @@ static bool fill_vfs_stat_for_fd(int fd, vfs_stat_info_t* info) { vfs_file_t* file = fd_get_file(fd); switch (file->mnt->type) { case FS_PROC: + case FS_DEV: info->is_dir = false; info->size = 0; break; @@ -362,6 +382,48 @@ static int sys_getdents64(uint64_t fd, char* buf, uint64_t buflen) { return (int)used; } + if (file->mnt->type == FS_DEV) { + static const char* dev_entries[] = {"null", "zero", "random", "urandom"}; + const uint64_t fixed = 4; + uint64_t total = fixed; + for (int i = 0; i < block_device_count; i++) { + if (block_devices[i].present && + (block_devices[i].type == BLOCK_DEVICE_AHCI || block_devices[i].type == BLOCK_DEVICE_NVME)) + total++; + } + + for (uint64_t i = entry_index; i < total; ++i) { + const char* name = NULL; + + if (i < fixed) { + name = dev_entries[i]; + } else { + uint64_t disk_idx = i - fixed; + uint64_t seen = 0; + for (int j = 0; j < block_device_count; j++) { + if (!block_devices[j].present) + continue; + if (block_devices[j].type != BLOCK_DEVICE_AHCI && block_devices[j].type != BLOCK_DEVICE_NVME) + continue; + + if (seen++ == disk_idx) { + name = block_devices[j].name; + break; + } + } + } + + if (!name) + continue; + + if (!emit_dirent(buf, buflen, &used, path_inode_hash(name), 2, name, i + 1)) + break; + + *pos = (uint32_t)(i + 1); + } + return (int)used; + } + if (file->mnt->type == FS_FAT16) { fat16_fs_t* fs = file->f.fat16.fs; uint16_t cluster = file->f.fat16.entry.first_cluster;