Virtual File System #10
@ -5,6 +5,8 @@
|
|||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef long ssize_t;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
if (gettid() == 0) // why are we the idle task?
|
if (gettid() == 0) // why are we the idle task?
|
||||||
@ -25,14 +27,42 @@ int main()
|
|||||||
|
|
||||||
sleep(2);
|
sleep(2);
|
||||||
|
|
||||||
|
const char* filename = "/sys/config";
|
||||||
|
|
||||||
|
printf("Opening %s for reading...\n", filename);
|
||||||
|
|
||||||
|
int fd = syscall(SYS_open, filename, 1);
|
||||||
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
char* variable = malloc(200);
|
perror("open");
|
||||||
*variable = 3;
|
// return 1;
|
||||||
printf("Allocated variable at address %p\n", variable);
|
}
|
||||||
free(variable);
|
else { printf("Got fd %d\n", fd); }
|
||||||
|
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
ssize_t nread = syscall(SYS_read, fd, sizeof(buf), buf);
|
||||||
|
if (nread < 0)
|
||||||
|
{
|
||||||
|
perror("read");
|
||||||
|
// return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf[nread] = 0;
|
||||||
|
|
||||||
|
printf("Read %zd bytes\n\n", nread);
|
||||||
|
|
||||||
|
printf("%s", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Press any key to restart.\n");
|
if (syscall(SYS_close, fd) < 0)
|
||||||
|
{
|
||||||
|
perror("close");
|
||||||
|
// return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n\nPress any key to restart.\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define EPERM 1
|
#define EPERM 1
|
||||||
|
#define ENOENT 2
|
||||||
|
#define EBADF 9
|
||||||
#define ENOMEM 12
|
#define ENOMEM 12
|
||||||
#define EINVAL 22
|
#define EINVAL 22
|
||||||
|
#define EMFILE 24
|
||||||
#define ENOSYS 38
|
#define ENOSYS 38
|
34
kernel/include/fs/FileDescriptor.h
Normal file
34
kernel/include/fs/FileDescriptor.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "fs/VFS.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct Descriptor
|
||||||
|
{
|
||||||
|
bool is_open()
|
||||||
|
{
|
||||||
|
return m_is_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_read()
|
||||||
|
{
|
||||||
|
return m_can_read && m_is_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
m_is_open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t read(size_t size, char* buffer);
|
||||||
|
|
||||||
|
void open(VFS::Node* node, bool can_read);
|
||||||
|
|
||||||
|
Descriptor(const Descriptor& other);
|
||||||
|
Descriptor();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_is_open;
|
||||||
|
bool m_can_read;
|
||||||
|
VFS::Node* m_node;
|
||||||
|
uint64_t m_offset;
|
||||||
|
};
|
30
kernel/include/fs/VFS.h
Normal file
30
kernel/include/fs/VFS.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef long ssize_t;
|
||||||
|
|
||||||
|
namespace VFS
|
||||||
|
{
|
||||||
|
struct Node;
|
||||||
|
|
||||||
|
typedef ssize_t (*node_read)(Node*, size_t, size_t, char*);
|
||||||
|
typedef Node* (*node_finddir)(Node*, const char*);
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
uint64_t inode;
|
||||||
|
uint64_t length;
|
||||||
|
node_read read_func;
|
||||||
|
node_finddir find_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
ssize_t read(Node* node, size_t offset, size_t length, char* buffer);
|
||||||
|
|
||||||
|
void mount_root(Node* root);
|
||||||
|
|
||||||
|
Node* resolve_path(const char* filename, Node* root = nullptr);
|
||||||
|
|
||||||
|
Node* root();
|
||||||
|
}
|
@ -12,6 +12,9 @@
|
|||||||
#define SYS_gettid 7
|
#define SYS_gettid 7
|
||||||
#define SYS_mmap 8
|
#define SYS_mmap 8
|
||||||
#define SYS_munmap 9
|
#define SYS_munmap 9
|
||||||
|
#define SYS_open 10
|
||||||
|
#define SYS_read 11
|
||||||
|
#define SYS_close 12
|
||||||
|
|
||||||
namespace Syscall
|
namespace Syscall
|
||||||
{
|
{
|
||||||
@ -27,4 +30,7 @@ void sys_rand(Context* context);
|
|||||||
void sys_getversion(Context* context, char* buffer, size_t max);
|
void sys_getversion(Context* context, char* buffer, size_t max);
|
||||||
void sys_gettid(Context* context);
|
void sys_gettid(Context* context);
|
||||||
void sys_mmap(Context* context, void* address, size_t size, int flags);
|
void sys_mmap(Context* context, void* address, size_t size, int flags);
|
||||||
void sys_munmap(Context* context, void* address, size_t size);
|
void sys_munmap(Context* context, void* address, size_t size);
|
||||||
|
void sys_open(Context* context, const char* filename, int flags);
|
||||||
|
void sys_read(Context* context, int fd, size_t size, char* buffer);
|
||||||
|
void sys_close(Context* context, int fd);
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "fs/FileDescriptor.h"
|
||||||
#include "interrupts/Context.h"
|
#include "interrupts/Context.h"
|
||||||
#include "sys/elf/Image.h"
|
#include "sys/elf/Image.h"
|
||||||
|
|
||||||
|
#define TASK_MAX_FDS 8
|
||||||
|
|
||||||
struct Task
|
struct Task
|
||||||
{
|
{
|
||||||
enum TaskState
|
enum TaskState
|
||||||
@ -36,6 +39,8 @@ struct Task
|
|||||||
bool is_user_task();
|
bool is_user_task();
|
||||||
|
|
||||||
ELFImage* image = nullptr;
|
ELFImage* image = nullptr;
|
||||||
|
|
||||||
|
Descriptor files[TASK_MAX_FDS];
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_context_from_task(Task& task, Context* ctx);
|
void set_context_from_task(Task& task, Context* ctx);
|
||||||
|
25
kernel/src/fs/FileDescriptor.cpp
Normal file
25
kernel/src/fs/FileDescriptor.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "fs/FileDescriptor.h"
|
||||||
|
|
||||||
|
Descriptor::Descriptor() : m_is_open(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Descriptor::Descriptor(const Descriptor& other)
|
||||||
|
: m_is_open(other.m_is_open), m_can_read(other.m_can_read), m_node(other.m_node), m_offset(other.m_offset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Descriptor::open(VFS::Node* node, bool can_read)
|
||||||
|
{
|
||||||
|
m_can_read = can_read;
|
||||||
|
m_node = node;
|
||||||
|
m_offset = 0;
|
||||||
|
m_is_open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Descriptor::read(size_t size, char* buffer)
|
||||||
|
{
|
||||||
|
ssize_t result = VFS::read(m_node, m_offset, size, buffer);
|
||||||
|
m_offset += result;
|
||||||
|
return result;
|
||||||
|
}
|
93
kernel/src/fs/VFS.cpp
Normal file
93
kernel/src/fs/VFS.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#define MODULE "vfs"
|
||||||
|
|
||||||
|
#include "fs/VFS.h"
|
||||||
|
#include "log/Log.h"
|
||||||
|
#include "std/stdlib.h"
|
||||||
|
#include "std/string.h"
|
||||||
|
|
||||||
|
static VFS::Node* vfs_root;
|
||||||
|
|
||||||
|
ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer)
|
||||||
|
{
|
||||||
|
if (!node)
|
||||||
|
{
|
||||||
|
kwarnln("read() failed: trying to read from nullptr");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!node->read_func)
|
||||||
|
{
|
||||||
|
kwarnln("read() failed: the chosen node doesn't support reading");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdbgln("read(): node %s (inode %ld), offset %zd, %zd bytes, into %p", node->name, node->inode, offset, length,
|
||||||
|
(void*)buffer);
|
||||||
|
|
||||||
|
return node->read_func(node, offset, length, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VFS::mount_root(Node* root)
|
||||||
|
{
|
||||||
|
if (!root)
|
||||||
|
{
|
||||||
|
kwarnln("mount_root() failed: attempted to mount nullptr");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (vfs_root)
|
||||||
|
{
|
||||||
|
kwarnln("mount_root() failed: root filesystem already mounted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
kinfoln("mounting node '%s' as vfs root", root->name);
|
||||||
|
vfs_root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFS::Node* VFS::root()
|
||||||
|
{
|
||||||
|
return vfs_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFS::Node* VFS::resolve_path(const char* filename, Node* root)
|
||||||
|
{
|
||||||
|
if (!root) root = vfs_root;
|
||||||
|
|
||||||
|
if (strlen(filename) == 0) return 0;
|
||||||
|
if (*filename == '/') // Absolute path.
|
||||||
|
{
|
||||||
|
filename++;
|
||||||
|
root = vfs_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* current_node = root;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
while (*filename == '/') { filename++; }
|
||||||
|
if (*filename == 0) { return current_node; }
|
||||||
|
|
||||||
|
size_t path_section_size = 0;
|
||||||
|
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||||
|
|
||||||
|
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||||
|
{
|
||||||
|
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||||
|
memcpy(buffer, filename, path_section_size);
|
||||||
|
buffer[path_section_size] = 0;
|
||||||
|
if (!current_node->find_func)
|
||||||
|
{
|
||||||
|
kwarnln("Current node has no way to find child nodes");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Node* child = current_node->find_func(current_node, buffer);
|
||||||
|
if (!child)
|
||||||
|
{
|
||||||
|
kwarnln("Current node did not find our target node");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
current_node = child;
|
||||||
|
kfree(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
filename += path_section_size;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "init/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
#include "bootboot.h"
|
#include "bootboot.h"
|
||||||
|
#include "fs/VFS.h"
|
||||||
#include "io/Serial.h"
|
#include "io/Serial.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
@ -14,6 +15,8 @@ extern BOOTBOOT bootboot;
|
|||||||
static void* initrd_base;
|
static void* initrd_base;
|
||||||
static bool initrd_initialized = false;
|
static bool initrd_initialized = false;
|
||||||
|
|
||||||
|
static VFS::Node initrd_root;
|
||||||
|
|
||||||
bool InitRD::is_initialized()
|
bool InitRD::is_initialized()
|
||||||
{
|
{
|
||||||
return initrd_initialized;
|
return initrd_initialized;
|
||||||
@ -112,10 +115,222 @@ void InitRD::for_each(void (*callback)(File& f))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define INITRD_MAX_FILES_IN_DIR 8
|
||||||
|
#define INITRD_MAX_FILES 32
|
||||||
|
|
||||||
|
namespace InitRD
|
||||||
|
{
|
||||||
|
struct Directory
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
int entries = 0;
|
||||||
|
VFS::Node* files[INITRD_MAX_FILES_IN_DIR];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void initrd_for_each_dir(void (*callback)(InitRD::Directory& f))
|
||||||
|
{
|
||||||
|
uint64_t block = 0;
|
||||||
|
uint64_t total_blocks = InitRD::get_total_blocks();
|
||||||
|
while (block < total_blocks)
|
||||||
|
{
|
||||||
|
InitRD::TarHeader* hdr = (InitRD::TarHeader*)InitRD::get_block(block);
|
||||||
|
if (!InitRD::is_valid_header(hdr))
|
||||||
|
{
|
||||||
|
block++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (hdr->typeflag == 53)
|
||||||
|
{
|
||||||
|
InitRD::Directory dir;
|
||||||
|
strncpy(dir.name, hdr->name, sizeof(dir.name));
|
||||||
|
callback(dir);
|
||||||
|
block++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto f = get_file(hdr);
|
||||||
|
block += get_file_size_in_blocks(f) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static InitRD::File files[32];
|
||||||
|
static uint32_t total_files = 0;
|
||||||
|
|
||||||
|
static InitRD::Directory dirs[32];
|
||||||
|
static uint32_t total_dirs = 0;
|
||||||
|
|
||||||
|
static VFS::Node nodes[63]; // One of the dirs is the initrd_root
|
||||||
|
static uint32_t total_nodes = 0;
|
||||||
|
|
||||||
|
ssize_t initrd_read(VFS::Node* node, size_t offset, size_t length, char* buffer)
|
||||||
|
{
|
||||||
|
if (!node) return -1;
|
||||||
|
if (node->inode >= total_files) return -1;
|
||||||
|
InitRD::File& file = files[node->inode];
|
||||||
|
if (offset > file.size) return -1;
|
||||||
|
if (offset + length > file.size) { length = file.size - offset; }
|
||||||
|
memcpy(buffer, (void*)((uintptr_t)file.addr + offset), length);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFS::Node* initrd_scan_dir(VFS::Node* node, const char* filename)
|
||||||
|
{
|
||||||
|
if (!node) return 0;
|
||||||
|
if (node->inode >= total_dirs) return 0;
|
||||||
|
InitRD::Directory dir = dirs[node->inode];
|
||||||
|
for (int i = 0; i < dir.entries; i++)
|
||||||
|
{
|
||||||
|
if (strncmp(dir.files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return dir.files[i]; }
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode)
|
||||||
|
{
|
||||||
|
const char* filename = dir.name;
|
||||||
|
VFS::Node* current_node = &initrd_root;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
while (*filename == '/') { filename++; }
|
||||||
|
if (*filename == 0) { return false; }
|
||||||
|
|
||||||
|
size_t path_section_size = 0;
|
||||||
|
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||||
|
|
||||||
|
if (filename[path_section_size]) // We are in a '/'
|
||||||
|
{
|
||||||
|
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||||
|
memcpy(buffer, filename, path_section_size);
|
||||||
|
buffer[path_section_size] = 0;
|
||||||
|
if (!current_node->find_func) { return false; }
|
||||||
|
VFS::Node* child = current_node->find_func(current_node, buffer);
|
||||||
|
if (!child) { return false; }
|
||||||
|
current_node = child;
|
||||||
|
kfree(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||||
|
{
|
||||||
|
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
|
||||||
|
|
||||||
|
if (!current_node->find_func) { return false; }
|
||||||
|
|
||||||
|
InitRD::Directory& parent = dirs[current_node->inode];
|
||||||
|
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
|
||||||
|
|
||||||
|
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||||
|
memcpy(buffer, filename, path_section_size);
|
||||||
|
buffer[path_section_size] = 0;
|
||||||
|
|
||||||
|
VFS::Node& node = nodes[total_nodes++];
|
||||||
|
node.inode = inode;
|
||||||
|
node.find_func = initrd_scan_dir;
|
||||||
|
node.length = 0;
|
||||||
|
strncpy(node.name, buffer, sizeof(node.name));
|
||||||
|
strncpy(dir.name, buffer, sizeof(dir.name));
|
||||||
|
|
||||||
|
parent.files[parent.entries++] = &node;
|
||||||
|
|
||||||
|
kfree(buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
filename += path_section_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool initrd_register_file(InitRD::File& f, uint64_t inode)
|
||||||
|
{
|
||||||
|
const char* filename = f.name;
|
||||||
|
VFS::Node* current_node = &initrd_root;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
while (*filename == '/') { filename++; }
|
||||||
|
if (*filename == 0) { return false; }
|
||||||
|
|
||||||
|
size_t path_section_size = 0;
|
||||||
|
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||||
|
|
||||||
|
if (filename[path_section_size]) // We are in a '/'
|
||||||
|
{
|
||||||
|
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||||
|
memcpy(buffer, filename, path_section_size);
|
||||||
|
buffer[path_section_size] = 0;
|
||||||
|
if (!current_node->find_func) { return false; }
|
||||||
|
VFS::Node* child = current_node->find_func(current_node, buffer);
|
||||||
|
if (!child) { return false; }
|
||||||
|
current_node = child;
|
||||||
|
kfree(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||||
|
{
|
||||||
|
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
|
||||||
|
|
||||||
|
if (!current_node->find_func) { return false; }
|
||||||
|
|
||||||
|
InitRD::Directory& parent = dirs[current_node->inode];
|
||||||
|
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
|
||||||
|
|
||||||
|
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||||
|
memcpy(buffer, filename, path_section_size);
|
||||||
|
buffer[path_section_size] = 0;
|
||||||
|
|
||||||
|
VFS::Node& node = nodes[total_nodes++];
|
||||||
|
node.inode = inode;
|
||||||
|
node.read_func = initrd_read;
|
||||||
|
node.length = f.size;
|
||||||
|
strncpy(node.name, buffer, sizeof(node.name));
|
||||||
|
strncpy(f.name, buffer, sizeof(f.name));
|
||||||
|
|
||||||
|
parent.files[parent.entries++] = &node;
|
||||||
|
kfree(buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
filename += path_section_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initrd_scan()
|
||||||
|
{
|
||||||
|
initrd_for_each_dir([](InitRD::Directory& dir) {
|
||||||
|
if (total_dirs >= 32) return;
|
||||||
|
uint64_t inode = total_dirs;
|
||||||
|
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
|
||||||
|
});
|
||||||
|
InitRD::for_each([](InitRD::File& f) {
|
||||||
|
if (total_files >= 32) return;
|
||||||
|
uint64_t inode = total_files;
|
||||||
|
if (initrd_register_file(f, inode)) files[total_files++] = f;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initrd_initialize_root()
|
||||||
|
{
|
||||||
|
initrd_root.length = 0;
|
||||||
|
initrd_root.inode = 0;
|
||||||
|
InitRD::Directory& root = dirs[0];
|
||||||
|
total_dirs++;
|
||||||
|
strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name));
|
||||||
|
strncpy(root.name, "initrd", sizeof(root.name));
|
||||||
|
initrd_root.find_func = initrd_scan_dir;
|
||||||
|
}
|
||||||
|
|
||||||
void InitRD::init()
|
void InitRD::init()
|
||||||
{
|
{
|
||||||
initrd_base =
|
initrd_base =
|
||||||
MemoryManager::get_unaligned_mappings((void*)bootboot.initrd_ptr, bootboot.initrd_size / PAGE_SIZE + 1);
|
MemoryManager::get_unaligned_mappings((void*)bootboot.initrd_ptr, bootboot.initrd_size / PAGE_SIZE + 1);
|
||||||
kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base);
|
kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base);
|
||||||
|
kdbgln("total blocks: %ld", get_total_blocks());
|
||||||
|
initrd_initialize_root();
|
||||||
|
initrd_scan();
|
||||||
|
VFS::mount_root(&initrd_root);
|
||||||
initrd_initialized = true;
|
initrd_initialized = true;
|
||||||
}
|
}
|
@ -4,6 +4,7 @@
|
|||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cpu/CPU.h"
|
#include "cpu/CPU.h"
|
||||||
|
#include "fs/VFS.h"
|
||||||
#include "gdt/GDT.h"
|
#include "gdt/GDT.h"
|
||||||
#include "init/Init.h"
|
#include "init/Init.h"
|
||||||
#include "init/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
@ -159,6 +160,27 @@ extern "C" void _start()
|
|||||||
|
|
||||||
kinfoln("Interrupts enabled");
|
kinfoln("Interrupts enabled");
|
||||||
|
|
||||||
|
kinfoln("Trying VFS");
|
||||||
|
|
||||||
|
VFS::Node* node = VFS::resolve_path("/sys/");
|
||||||
|
if (!node) { kerrorln("Unable to find /sys in VFS"); }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kinfoln("Found '%s'", node->name);
|
||||||
|
node = VFS::resolve_path("config", node);
|
||||||
|
if (!node) kerrorln("unable to find /sys/config in VFS");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kinfoln("Found '%s'", node->name);
|
||||||
|
char* buffer = (char*)kmalloc(node->length + 1);
|
||||||
|
buffer[node->length] = 0;
|
||||||
|
ssize_t nread = VFS::read(node, 0, node->length, buffer);
|
||||||
|
kdbgln("Read %zd bytes", nread);
|
||||||
|
kinfoln("Read: %s", buffer);
|
||||||
|
kfree(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PCI::scan([](PCI::Device& dev) {
|
PCI::scan([](PCI::Device& dev) {
|
||||||
kinfoln("Found PCI device %x:%x, %s", dev.id().vendor, dev.id().device, pci_type_name(dev.type()));
|
kinfoln("Found PCI device %x:%x, %s", dev.id().vendor, dev.id().device, pci_type_name(dev.type()));
|
||||||
});
|
});
|
||||||
|
@ -26,6 +26,9 @@ void Syscall::entry(Context* context)
|
|||||||
case SYS_gettid: sys_gettid(context); break;
|
case SYS_gettid: sys_gettid(context); break;
|
||||||
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
|
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
|
||||||
case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break;
|
case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break;
|
||||||
|
case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi); break;
|
||||||
|
case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break;
|
||||||
|
case SYS_close: sys_close(context, (int)context->rdi); break;
|
||||||
default: context->rax = -ENOSYS; break;
|
default: context->rax = -ENOSYS; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,108 @@
|
|||||||
|
#define MODULE "stdio"
|
||||||
|
|
||||||
|
#include "errno.h"
|
||||||
#include "interrupts/Context.h"
|
#include "interrupts/Context.h"
|
||||||
#include "io/Serial.h"
|
#include "io/Serial.h"
|
||||||
|
#include "log/Log.h"
|
||||||
#include "render/TextRenderer.h"
|
#include "render/TextRenderer.h"
|
||||||
|
#include "thread/Scheduler.h"
|
||||||
|
#include "thread/Task.h"
|
||||||
|
|
||||||
|
#define STDIO_FAIL(function, error) kwarnln("%s failed with %s", #function, #error)
|
||||||
|
|
||||||
void sys_write(Context* context, const char* addr, size_t size)
|
void sys_write(Context* context, const char* addr, size_t size)
|
||||||
{
|
{
|
||||||
context->rax = size;
|
context->rax = size;
|
||||||
TextRenderer::write(addr, size);
|
TextRenderer::write(addr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_open(Context* context, const char* filename, int flags)
|
||||||
|
{
|
||||||
|
Task* current_task = Scheduler::current_task();
|
||||||
|
int fd = -1;
|
||||||
|
for (fd = 0; fd < TASK_MAX_FDS; fd++)
|
||||||
|
{
|
||||||
|
if (!current_task->files[fd].is_open()) break;
|
||||||
|
}
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
STDIO_FAIL(open, EMFILE);
|
||||||
|
context->rax = -EMFILE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VFS::Node* node = VFS::resolve_path(filename);
|
||||||
|
if (!node)
|
||||||
|
{
|
||||||
|
STDIO_FAIL(open, ENOENT);
|
||||||
|
context->rax = -ENOENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_task->files[fd].open(node,
|
||||||
|
(bool)flags); // FIXME: Implement more flags. (right now, 1 is can_read, 0 is not)
|
||||||
|
context->rax = fd;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_read(Context* context, int fd, size_t size, char* buffer)
|
||||||
|
{
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
STDIO_FAIL(read, EINVAL);
|
||||||
|
context->rax = -EINVAL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fd >= TASK_MAX_FDS)
|
||||||
|
{
|
||||||
|
STDIO_FAIL(read, EBADF);
|
||||||
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
STDIO_FAIL(read, EBADF);
|
||||||
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Task* current_task = Scheduler::current_task();
|
||||||
|
if (!current_task->files[fd].is_open())
|
||||||
|
{
|
||||||
|
STDIO_FAIL(read, EBADF);
|
||||||
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!current_task->files[fd].can_read())
|
||||||
|
{
|
||||||
|
STDIO_FAIL(read, EBADF);
|
||||||
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ssize_t result = current_task->files[fd].read(size, buffer);
|
||||||
|
context->rax = (size_t)result;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_close(Context* context, int fd)
|
||||||
|
{
|
||||||
|
if (fd >= TASK_MAX_FDS)
|
||||||
|
{
|
||||||
|
STDIO_FAIL(close, EBADF);
|
||||||
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
STDIO_FAIL(close, EBADF);
|
||||||
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Task* current_task = Scheduler::current_task();
|
||||||
|
if (!current_task->files[fd].is_open())
|
||||||
|
{
|
||||||
|
STDIO_FAIL(close, EBADF);
|
||||||
|
context->rax = -EBADF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_task->files[fd].close();
|
||||||
|
context->rax = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
@ -21,7 +21,7 @@ typedef struct stackframe
|
|||||||
void StackTracer::trace()
|
void StackTracer::trace()
|
||||||
{
|
{
|
||||||
stackframe* frame = (stackframe*)m_base_pointer;
|
stackframe* frame = (stackframe*)m_base_pointer;
|
||||||
while (Memory::is_kernel_address((uintptr_t)frame))
|
while (frame)
|
||||||
{
|
{
|
||||||
char symbol_name[512];
|
char symbol_name[512];
|
||||||
get_symbol_name(frame->instruction, symbol_name);
|
get_symbol_name(frame->instruction, symbol_name);
|
||||||
@ -32,11 +32,6 @@ void StackTracer::trace()
|
|||||||
|
|
||||||
void StackTracer::trace_with_ip(uintptr_t ip)
|
void StackTracer::trace_with_ip(uintptr_t ip)
|
||||||
{
|
{
|
||||||
if (!Memory::is_kernel_address(ip))
|
|
||||||
{
|
|
||||||
printf("(user stack)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char symbol_name[512];
|
char symbol_name[512];
|
||||||
get_symbol_name(ip, symbol_name);
|
get_symbol_name(ip, symbol_name);
|
||||||
printf("%lx: %s\n", ip, symbol_name);
|
printf("%lx: %s\n", ip, symbol_name);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
do { \
|
do { \
|
||||||
if (rc < 0) \
|
if (rc < 0) \
|
||||||
{ \
|
{ \
|
||||||
errno = (int)rc; \
|
errno = (int)(-rc); \
|
||||||
return -1; \
|
return -1; \
|
||||||
} \
|
} \
|
||||||
return (type)rc; \
|
return (type)rc; \
|
||||||
|
@ -4,8 +4,11 @@
|
|||||||
extern int errno;
|
extern int errno;
|
||||||
|
|
||||||
#define EPERM 1
|
#define EPERM 1
|
||||||
|
#define ENOENT 2
|
||||||
|
#define EBADF 9
|
||||||
#define ENOMEM 12
|
#define ENOMEM 12
|
||||||
#define EINVAL 22
|
#define EINVAL 22
|
||||||
|
#define EMFILE 24
|
||||||
#define ENOSYS 38
|
#define ENOSYS 38
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -11,6 +11,9 @@
|
|||||||
#define SYS_gettid 7
|
#define SYS_gettid 7
|
||||||
#define SYS_mmap 8
|
#define SYS_mmap 8
|
||||||
#define SYS_munmap 9
|
#define SYS_munmap 9
|
||||||
|
#define SYS_open 10
|
||||||
|
#define SYS_read 11
|
||||||
|
#define SYS_close 12
|
||||||
|
|
||||||
#ifndef __want_syscalls
|
#ifndef __want_syscalls
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -121,7 +121,11 @@ extern "C"
|
|||||||
case EINVAL: return "Invalid argument";
|
case EINVAL: return "Invalid argument";
|
||||||
case ENOMEM: return "Out of memory";
|
case ENOMEM: return "Out of memory";
|
||||||
case ENOSYS: return "Function not implemented";
|
case ENOSYS: return "Function not implemented";
|
||||||
default: return 0;
|
case ENOENT: return "No such file or directory";
|
||||||
|
case EBADF: return "Bad file descriptor";
|
||||||
|
case EMFILE: return "Too many open files";
|
||||||
|
case 0: return "Success";
|
||||||
|
default: return (char*)(unsigned long int)errnum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,15 +35,18 @@ extern "C"
|
|||||||
case SYS_gettid:
|
case SYS_gettid:
|
||||||
case SYS_rand: result = __luna_syscall0(number); break;
|
case SYS_rand: result = __luna_syscall0(number); break;
|
||||||
case SYS_exit:
|
case SYS_exit:
|
||||||
|
case SYS_close:
|
||||||
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
|
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
|
||||||
case SYS_write:
|
case SYS_write:
|
||||||
case SYS_munmap:
|
case SYS_munmap:
|
||||||
|
case SYS_open:
|
||||||
case SYS_getversion: {
|
case SYS_getversion: {
|
||||||
arg arg0 = va_arg(ap, arg);
|
arg arg0 = va_arg(ap, arg);
|
||||||
arg arg1 = va_arg(ap, arg);
|
arg arg1 = va_arg(ap, arg);
|
||||||
result = __luna_syscall2(number, arg0, arg1);
|
result = __luna_syscall2(number, arg0, arg1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SYS_read:
|
||||||
case SYS_mmap: {
|
case SYS_mmap: {
|
||||||
arg arg0 = va_arg(ap, arg);
|
arg arg0 = va_arg(ap, arg);
|
||||||
arg arg1 = va_arg(ap, arg);
|
arg arg1 = va_arg(ap, arg);
|
||||||
|
Loading…
Reference in New Issue
Block a user