vfs - kinda good vfs implementation
This commit is contained in:
parent
cfc9159ad9
commit
1e84bcedc9
13 changed files with 3650 additions and 12 deletions
56
kernel/src/dbg/sym.c
Normal file
56
kernel/src/dbg/sym.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "dbg/sym.h"
|
||||
#include "exec/elf.h"
|
||||
#include "limine.h"
|
||||
#include "sys/errhnd/panic.h"
|
||||
#include "sys/log.h"
|
||||
#include <lib/string.h>
|
||||
#include <mm/liballoc/liballoc.h>
|
||||
|
||||
static Elf64_Sym *__ksym_symtab;
|
||||
static char *__ksym_strtab;
|
||||
static int __ksym_symcount = 0;
|
||||
|
||||
__attribute__((used, section(".limine_requests"))) static volatile struct
|
||||
limine_executable_file_request exec_file_rq = {
|
||||
.id = LIMINE_EXECUTABLE_FILE_REQUEST, .revision = 3};
|
||||
|
||||
void ksym_init() {
|
||||
char *img = exec_file_rq.response->executable_file->address;
|
||||
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)img;
|
||||
if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3) {
|
||||
panic("kernel - how did i even boot? *starts galaxy brain meme*");
|
||||
}
|
||||
|
||||
Elf64_Shdr *shdr = (Elf64_Shdr *)(img + ehdr->e_shoff);
|
||||
const char *shstrtab = (char *)img + shdr[ehdr->e_shstrndx].sh_offset;
|
||||
|
||||
for (int j = 0; j < ehdr->e_shnum; j++) {
|
||||
if (shdr[j].sh_type == SHT_SYMTAB) {
|
||||
__ksym_symtab = (Elf64_Sym *)(img + shdr[j].sh_offset);
|
||||
__ksym_symcount = shdr[j].sh_size / shdr[j].sh_entsize;
|
||||
} else if (shdr[j].sh_type == SHT_STRTAB &&
|
||||
strcmp(shstrtab + shdr[j].sh_name, ".strtab") == 0) {
|
||||
__ksym_strtab = (char *)(img + shdr[j].sh_offset);
|
||||
}
|
||||
}
|
||||
|
||||
log("kernel - loaded %d symbols\n", __ksym_symcount);
|
||||
}
|
||||
|
||||
func *ksym_fromip(uint64_t ip) {
|
||||
for (int i = 0; i < __ksym_symcount; i++) {
|
||||
uint64_t value = __ksym_symtab[i].st_value;
|
||||
uint64_t size = __ksym_symtab[i].st_size;
|
||||
|
||||
if (value <= ip && ip < (value + size)) {
|
||||
func *f = malloc(sizeof(func));
|
||||
f->base = value;
|
||||
f->ip = ip;
|
||||
f->name = (__ksym_strtab + __ksym_symtab[i].st_name);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
12
kernel/src/dbg/sym.h
Normal file
12
kernel/src/dbg/sym.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "mm/vmm.h"
|
||||
|
||||
typedef struct func {
|
||||
uint64_t base;
|
||||
uint64_t ip;
|
||||
char *name;
|
||||
} func;
|
||||
|
||||
void ksym_init();
|
||||
func *ksym_fromip(uint64_t ip);
|
|
@ -122,4 +122,32 @@ typedef struct {
|
|||
Elf64_Ehdr *ehdr;
|
||||
} elf_program_t;
|
||||
|
||||
program_t *elf_load(char *data, int user);
|
||||
program_t *elf_load(char *data, int user);
|
||||
|
||||
// Those aren't used for loading, but used by
|
||||
// the kernel to resolve symbols from an instruction
|
||||
// pointer.
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
|
||||
typedef struct {
|
||||
uint32_t st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
uint16_t st_shndx;
|
||||
Elf64_Addr st_value;
|
||||
uint64_t st_size;
|
||||
} Elf64_Sym;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sh_name;
|
||||
uint32_t sh_type;
|
||||
uint64_t sh_flags;
|
||||
Elf64_Addr sh_addr;
|
||||
Elf64_Off sh_offset;
|
||||
uint64_t sh_size;
|
||||
uint32_t sh_link;
|
||||
uint32_t sh_info;
|
||||
uint64_t sh_addralign;
|
||||
uint64_t sh_entsize;
|
||||
} Elf64_Shdr;
|
||||
|
|
101
kernel/src/fs/hellofs.c
Normal file
101
kernel/src/fs/hellofs.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "fs/hellofs.h"
|
||||
#include "fs/vfs.h"
|
||||
#include <mm/liballoc/liballoc.h>
|
||||
#include <mm/memop.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
static int hellofs_read(vnode_t *vn, void *buf, size_t off, size_t size) {
|
||||
if (!vn || !buf || size <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *hello = "hello";
|
||||
const size_t hello_len = 5; // strlen("hello")
|
||||
char *cbuf = (char *)buf;
|
||||
size_t bytes_written = 0;
|
||||
|
||||
while (bytes_written < size) {
|
||||
size_t pos = off % hello_len; // Position within "hello"
|
||||
size_t remaining = hello_len - pos; // Remaining bytes in current "hello"
|
||||
size_t to_copy = (size - bytes_written < remaining) ?
|
||||
(size - bytes_written) : remaining;
|
||||
|
||||
memcpy(cbuf + bytes_written, hello + pos, to_copy);
|
||||
bytes_written += to_copy;
|
||||
off += to_copy;
|
||||
}
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
vnode_ops_t hellofs_hello_ops = {
|
||||
.read = hellofs_read,
|
||||
.lookup = NULL,
|
||||
};
|
||||
|
||||
static int hellofs_lookup(vnode_t *vn, const char *name, vnode_t **out) {
|
||||
if (!vn || !name || !out) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(name, "hello") == 0) {
|
||||
*out = vfs_create_node("hello", VN_FILE);
|
||||
if (*out) {
|
||||
(*out)->ops = &hellofs_hello_ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
} else {
|
||||
*out = NULL; // Not found
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
vnode_ops_t hellofs_root_ops = {
|
||||
.read = NULL,
|
||||
.lookup = hellofs_lookup,
|
||||
};
|
||||
|
||||
static int hellofs_mount(fs_t *fs, vnode_t *mountpoint) {
|
||||
if (!fs || !mountpoint) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// mountpoint list isn't implemented.
|
||||
|
||||
/*mountpoint_t *mp = (mountpoint_t *)malloc(sizeof(mountpoint_t));
|
||||
if (!mp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(mp, 0, sizeof(mountpoint_t));
|
||||
strncpy(mp->name, fs->name, sizeof(mp->name) - 1);
|
||||
mp->fs = fs;
|
||||
mp->mountpoint = mountpoint;*/
|
||||
|
||||
// Mounting is essentially just putting the file system's root directory operations
|
||||
// on the mountpoint vnode.
|
||||
mountpoint->ops = &hellofs_root_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs_t *hellofs_init() {
|
||||
fs_t *fs = (fs_t *)malloc(sizeof(fs_t));
|
||||
if (!fs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(fs, 0, sizeof(fs_t));
|
||||
strncpy(fs->name, "hellofs", sizeof(fs->name) - 1);
|
||||
|
||||
fs->mount = hellofs_mount;
|
||||
fs->root = vfs_create_node("/", VN_DIR);
|
||||
if (!fs->root) {
|
||||
free(fs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fs;
|
||||
}
|
5
kernel/src/fs/hellofs.h
Normal file
5
kernel/src/fs/hellofs.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <fs/vfs.h>
|
||||
|
||||
fs_t *hellofs_init(void);
|
|
@ -2,6 +2,99 @@
|
|||
#include "lib/string.h"
|
||||
#include "mm/liballoc/liballoc.h"
|
||||
#include "mm/memop.h"
|
||||
#include "sys/errhnd/panic.h"
|
||||
|
||||
vnode_t *root = NULL;
|
||||
|
||||
void vfs_init() {
|
||||
root = vfs_create_node("/", VN_DIR);
|
||||
if (!root) {
|
||||
panic("vfs - failed to create root node");
|
||||
}
|
||||
root->parent = root; // Root's parent is itself
|
||||
}
|
||||
|
||||
// Not worth adding to the header, since it should only lookup
|
||||
// for files/directories in dir, without going deeper.
|
||||
int vfs_lookup(vnode_t *dir, const char *name, vnode_t **out) {
|
||||
if (!dir || !name)
|
||||
return -1;
|
||||
|
||||
if (dir->ops && dir->ops->lookup) {
|
||||
return dir->ops->lookup(dir, name, out);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_open(vnode_t *curdir, const char *path, vnode_t **out) {
|
||||
if (strcmp(path, ".") == 0) {
|
||||
*out = curdir;
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(path, "..") == 0) {
|
||||
*out = curdir->parent;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *path_copy = strdup(path);
|
||||
if (!path_copy) {
|
||||
*out = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
vnode_t *cur_node = path[0] == '/' ? root : curdir;
|
||||
char *token = strtok(path_copy, "/");
|
||||
|
||||
while (token) {
|
||||
vnode_t *next;
|
||||
vfs_lookup(cur_node, token, &next);
|
||||
if (!next) {
|
||||
free(path_copy);
|
||||
*out = NULL;
|
||||
return -1;
|
||||
}
|
||||
cur_node = next;
|
||||
token = strtok(NULL, "/");
|
||||
}
|
||||
|
||||
free(path_copy);
|
||||
*out = cur_node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_mount(char *path, fs_t *fs) {
|
||||
if (!fs || !path) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
vnode_t *mp;
|
||||
if (strcmp(path, "/") == 0) {
|
||||
mp = root;
|
||||
} else {
|
||||
vfs_open(root, path, &mp);
|
||||
}
|
||||
|
||||
if (fs->mount == NULL)
|
||||
return -1; // why allocating a fs without the capability to mount to a node? lmao
|
||||
|
||||
return fs->mount(fs, mp);
|
||||
}
|
||||
|
||||
int vfs_unmount(char *path) {
|
||||
(void)path;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_read(vnode_t *vn, void *buf, size_t off, size_t size) {
|
||||
if (!vn || !buf || off < 0 || size <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vn->ops && vn->ops->read) {
|
||||
return vn->ops->read(vn, buf, off, size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
vnode_t *vfs_create_node(char *name, vnode_type_t type) {
|
||||
vnode_t *node = (vnode_t *)malloc(sizeof(vnode_t));
|
||||
|
|
|
@ -12,14 +12,14 @@ typedef uint32_t vnode_type_t;
|
|||
|
||||
typedef struct vnode_ops {
|
||||
int (*read)(struct vnode *vn, void *buf, size_t off, size_t size);
|
||||
struct vnode *(*lookup)(struct vnode *vn, const char *name);
|
||||
int (*lookup)(struct vnode *vn, const char *name, struct vnode **out);
|
||||
} vnode_ops_t;
|
||||
|
||||
typedef struct vnode {
|
||||
char name[256];
|
||||
vnode_type_t type;
|
||||
uint32_t refcount;
|
||||
// struct vnode* parent;
|
||||
struct vnode* parent; // If this vnode exists, then it's parent too.
|
||||
// struct vnode* child;
|
||||
// struct vnode* next;
|
||||
|
||||
|
@ -36,11 +36,12 @@ typedef struct mountpoint {
|
|||
typedef struct fs {
|
||||
char name[32];
|
||||
struct vnode *root;
|
||||
int (*mount)(struct vnode *mountpoint);
|
||||
int (*mount)(struct fs *fs, struct vnode *mountpoint);
|
||||
} fs_t;
|
||||
|
||||
void vfs_init(void);
|
||||
int vfs_mount(char *path, fs_t *fs);
|
||||
int vfs_unmount(char *path);
|
||||
int vfs_open(const char *path, vnode_t **result);
|
||||
int vfs_open(vnode_t *curdir, const char *path, vnode_t **out);
|
||||
int vfs_read(vnode_t *vn, void *buf, size_t off, size_t size);
|
||||
vnode_t *vfs_create_node(char *name, vnode_type_t type);
|
|
@ -1,7 +1,10 @@
|
|||
#include <lib/string.h>
|
||||
#include <mm/liballoc/liballoc.h>
|
||||
#include <mm/memop.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static char *olds;
|
||||
|
||||
int strlen(const char *str) {
|
||||
int len = 0;
|
||||
while (str[len])
|
||||
|
@ -78,3 +81,54 @@ char *strncpy(char *dest, const char *src, size_t n) {
|
|||
dest[i] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define DICT_LEN 256
|
||||
|
||||
static int *create_delim_dict(char *delim) {
|
||||
int *d = (int *)malloc(sizeof(int) * DICT_LEN);
|
||||
memset((void *)d, 0, sizeof(int) * DICT_LEN);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < strlen(delim); i++) {
|
||||
d[delim[i]] = 1;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
char *strtok(char *str, char *delim) {
|
||||
|
||||
static char *last, *to_free;
|
||||
int *deli_dict = create_delim_dict(delim);
|
||||
|
||||
if (!deli_dict) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (str) {
|
||||
last = (char *)malloc(strlen(str) + 1);
|
||||
if (!last) {
|
||||
free(deli_dict);
|
||||
}
|
||||
to_free = last;
|
||||
strcpy(last, str);
|
||||
}
|
||||
|
||||
while (deli_dict[*last] && *last != '\0') {
|
||||
last++;
|
||||
}
|
||||
str = last;
|
||||
if (*last == '\0') {
|
||||
free(deli_dict);
|
||||
free(to_free);
|
||||
return NULL;
|
||||
}
|
||||
while (*last != '\0' && !deli_dict[*last]) {
|
||||
last++;
|
||||
}
|
||||
|
||||
*last = '\0';
|
||||
last++;
|
||||
|
||||
free(deli_dict);
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -8,4 +8,5 @@ char *strcpy(char *dest, const char *src);
|
|||
char *strrchr(const char *s, int c);
|
||||
int oct2bin(unsigned char *str, int size);
|
||||
char *strdup(const char *str);
|
||||
char *strncpy(char *dest, const char *src, size_t n);
|
||||
char *strncpy(char *dest, const char *src, size_t n);
|
||||
char *strtok(char *str, char *delim);
|
|
@ -1,10 +1,12 @@
|
|||
#include "arch/x86_64/pit.h"
|
||||
#include "arch/x86_64/smp.h"
|
||||
#include "arch/x86_64/sse.h"
|
||||
#include "dbg/sym.h"
|
||||
#include "dev/ioapic.h"
|
||||
#include "dev/lapic.h"
|
||||
#include "exec/elf.h"
|
||||
#include "exec/exec.h"
|
||||
#include "fs/hellofs.h"
|
||||
#include "mm/liballoc/liballoc.h"
|
||||
#include "mm/pmm.h"
|
||||
#include "mm/vma.h"
|
||||
|
@ -57,10 +59,6 @@ struct flanterm_context *ft_ctx;
|
|||
|
||||
char kstack[8192];
|
||||
|
||||
void test3() { *((uint8_t*)0x0) = (uint8_t)0xFF; }
|
||||
void test2() { test3();}
|
||||
void test1() { test2(); }
|
||||
|
||||
void __kmain(void) {
|
||||
if (framebuffer_request.response != NULL) {
|
||||
|
||||
|
@ -92,6 +90,14 @@ void __kmain(void) {
|
|||
asm("hlt");
|
||||
}
|
||||
|
||||
ksym_init();
|
||||
func *f = ksym_fromip((uint64_t)__kmain);
|
||||
if (f) {
|
||||
log("ksym: found %s at %p\n", f->name, f->ip);
|
||||
} else {
|
||||
log("ksym: not found\n");
|
||||
}
|
||||
|
||||
acpi_init();
|
||||
madt_init();
|
||||
ioapic_init();
|
||||
|
@ -99,9 +105,22 @@ void __kmain(void) {
|
|||
pit_init();
|
||||
smp_init();
|
||||
|
||||
vfs_init();
|
||||
fs_t *hellofs = hellofs_init();
|
||||
vfs_mount("/", hellofs);
|
||||
|
||||
vnode_t *vn;
|
||||
vfs_open(NULL, "/hello", &vn);
|
||||
if (vn) {
|
||||
char buf[100];
|
||||
vfs_read(vn, buf, 2, sizeof(buf));
|
||||
log("Read from /hello: %s\n", buf);
|
||||
} else {
|
||||
log("Failed to open /hello\n");
|
||||
}
|
||||
|
||||
syscall_init();
|
||||
sched_init();
|
||||
test1();
|
||||
|
||||
// vfs_init();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ __attribute__((
|
|||
.revision = 3,
|
||||
.mode = LIMINE_PAGING_MODE_X86_64_4LVL};
|
||||
|
||||
__attribute__((used, section(".limine_requests"))) static volatile struct
|
||||
__attribute__((used, section(".limine_requests"))) volatile struct
|
||||
limine_executable_address_request karq = {
|
||||
.id = LIMINE_EXECUTABLE_ADDRESS_REQUEST,
|
||||
.revision = 0,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue