e6e8b1209b
Finally we got usermode working again, It took awhile but we got it done. A few things we did in this commit: - Simplified GDT entry initialization in gdt.c for kernel and user segments. - Fixed TSS structure for task switching. - Implemented cr2 handling in a page fault. - Enhanced user stack setup in usermode.c to return the correct RSP. - Improved syscall implementation in syscall.c, including new syscall numbers. - Updated syscall entry to correctly handle context switching and argument passing. - Refactored init.c to demonstrate file operations using syscalls. - Added new syscalls for file operations in syscalls.h. - Modified VFS to handle leading slashes in paths correctly. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
212 lines
4.8 KiB
C
212 lines
4.8 KiB
C
#include "vfs.h"
|
|
#include <video/render.h>
|
|
#include <arch/x86_64/e9.h>
|
|
#include "mp/spinlock.h"
|
|
#include "stdio.h"
|
|
#include "mm/memory.h"
|
|
#include "string.h"
|
|
|
|
static spinlock_t s_vfs_lock = SPINLOCK_INIT;
|
|
static vfs_file_t vfs_fd_table[VFS_MAX_FDS];
|
|
|
|
typedef struct {
|
|
const char* path;
|
|
int (*read)(void* buf, size_t len);
|
|
int (*write)(const void* buf, size_t len);
|
|
} vfs_chardev_t;
|
|
|
|
#define VFS_MAX_CHARDEVS 8
|
|
static vfs_chardev_t s_chardevs[VFS_MAX_CHARDEVS];
|
|
static int s_num_chardevs = 0;
|
|
|
|
int VFS_RegisterCharDev(const char* path,
|
|
int (*read)(void* buf, size_t len),
|
|
int (*write)(const void* buf, size_t len))
|
|
{
|
|
if (s_num_chardevs >= VFS_MAX_CHARDEVS) {
|
|
printf("VFS: too many char devices!\n");
|
|
return -1;
|
|
}
|
|
s_chardevs[s_num_chardevs].path = path;
|
|
s_chardevs[s_num_chardevs].read = read;
|
|
s_chardevs[s_num_chardevs].write = write;
|
|
printf("VFS: registered chardev %s\n", path);
|
|
s_num_chardevs++;
|
|
return 0;
|
|
}
|
|
|
|
fd_t VFS_Open_internal(const char* path)
|
|
{
|
|
const char* p = path;
|
|
if (*p == '/') p++;
|
|
|
|
for (int i = 0; i < s_num_chardevs; i++) {
|
|
if (strcmp(s_chardevs[i].path, p) == 0) {
|
|
for (int fd = 4; fd < VFS_MAX_FDS; fd++) {
|
|
if (!vfs_fd_table[fd].used) {
|
|
vfs_fd_table[fd].used = true;
|
|
vfs_fd_table[fd].type = VFS_NODE_CHARDEV;
|
|
vfs_fd_table[fd].offset = 0;
|
|
vfs_fd_table[fd].chardev.dev_idx = i;
|
|
return fd;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
uint32_t ino = ext2_resolve_path(p);
|
|
if (ino == 0)
|
|
return -1;
|
|
|
|
// find free fd
|
|
for (int i = 4; i < VFS_MAX_FDS; i++)
|
|
{
|
|
if (!vfs_fd_table[i].used)
|
|
{
|
|
vfs_fd_table[i].used = true;
|
|
vfs_fd_table[i].type = VFS_NODE_EXT2;
|
|
vfs_fd_table[i].offset = 0;
|
|
vfs_fd_table[i].ext2.inode_num = ino;
|
|
|
|
if (!ext2_read_inode(ino, &vfs_fd_table[i].ext2.inode))
|
|
return -1;
|
|
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
fd_t VFS_Open(const char* path) {
|
|
uint64_t flags;
|
|
spinlock_acquire_irqsave(&s_vfs_lock, &flags);
|
|
fd_t fd = VFS_Open_internal(path);
|
|
spinlock_release_irqrestore(&s_vfs_lock, flags);
|
|
return fd;
|
|
}
|
|
|
|
int VFS_Close_internal(fd_t fd)
|
|
{
|
|
if (fd < 0 || fd >= VFS_MAX_FDS)
|
|
return -1;
|
|
|
|
vfs_fd_table[fd].used = false;
|
|
return 0;
|
|
}
|
|
|
|
int VFS_Close(fd_t fd) {
|
|
uint64_t flags;
|
|
spinlock_acquire_irqsave(&s_vfs_lock, &flags);
|
|
int resp = VFS_Close_internal(fd);
|
|
spinlock_release_irqrestore(&s_vfs_lock, flags);
|
|
return resp;
|
|
}
|
|
|
|
int VFS_Read(fd_t fd, uint8_t* buf, size_t size)
|
|
{
|
|
if (fd < 0 || fd >= VFS_MAX_FDS)
|
|
return -1;
|
|
|
|
vfs_file_t* file = &vfs_fd_table[fd];
|
|
|
|
if (!file->used)
|
|
return -1;
|
|
|
|
switch (file->type)
|
|
{
|
|
case VFS_NODE_EXT2:
|
|
{
|
|
uint32_t file_size = file->ext2.inode.i_size;
|
|
|
|
if (file->offset >= file_size)
|
|
return 0;
|
|
|
|
// clamp read
|
|
if (file->offset + size > file_size)
|
|
size = file_size - file->offset;
|
|
|
|
// naive: read whole file then slice
|
|
uint8_t* tmp = kmalloc(file_size);
|
|
if (!ext2_read_file(&file->ext2.inode, tmp))
|
|
return -1;
|
|
|
|
for (size_t i = 0; i < size; i++)
|
|
buf[i] = tmp[file->offset + i];
|
|
|
|
file->offset += size;
|
|
return size;
|
|
}
|
|
|
|
case VFS_NODE_CHARDEV:
|
|
{
|
|
int idx = file->chardev.dev_idx;
|
|
if (idx < 0 || idx >= s_num_chardevs || !s_chardevs[idx].read)
|
|
return -1;
|
|
return s_chardevs[idx].read(buf, size);
|
|
}
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int VFS_Write(fd_t file, uint8_t* data, size_t size)
|
|
{
|
|
switch (file)
|
|
{
|
|
case VFS_FD_STDIN:
|
|
return 0;
|
|
|
|
case VFS_FD_STDOUT:
|
|
for (size_t i = 0; i < size; i++)
|
|
putchar(data[i]);
|
|
return size;
|
|
case VFS_FD_STDERR:
|
|
for (size_t i = 0; i < size; i++)
|
|
putchar(data[i]);
|
|
return size;
|
|
|
|
case VFS_FD_DEBUG:
|
|
for (size_t i = 0; i < size; i++)
|
|
e9_putc(data[i]);
|
|
return size;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (file < 0 || file >= VFS_MAX_FDS)
|
|
return -1;
|
|
|
|
vfs_file_t* f = &vfs_fd_table[file];
|
|
|
|
if (!f->used)
|
|
return -1;
|
|
|
|
if (f->type == VFS_NODE_EXT2)
|
|
{
|
|
if (!ext2_write_file(
|
|
&f->ext2.inode,
|
|
f->ext2.inode_num,
|
|
data,
|
|
size,
|
|
EXT2_WRITE_APPEND))
|
|
return -1;
|
|
|
|
return size;
|
|
}
|
|
|
|
if (f->type == VFS_NODE_CHARDEV)
|
|
{
|
|
int idx = f->chardev.dev_idx;
|
|
if (idx >= 0 && idx < s_num_chardevs && s_chardevs[idx].write)
|
|
return s_chardevs[idx].write(data, size);
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
} |