Compare commits
9 Commits
f6e783ea45
...
b67011c626
Author | SHA1 | Date | |
---|---|---|---|
b67011c626 | |||
0f47f59364 | |||
2f46e46aa4 | |||
80ab982fe4 | |||
53a4b3b85e | |||
12cf37d0a7 | |||
e764647133 | |||
b1fcfd0d74 | |||
e67ef7778c |
@ -14,14 +14,20 @@ struct Descriptor
|
||||
return m_can_read && m_is_open;
|
||||
}
|
||||
|
||||
bool can_write()
|
||||
{
|
||||
return m_can_write && m_is_open;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
ssize_t read(size_t size, char* buffer);
|
||||
ssize_t write(size_t size, const char* buffer);
|
||||
|
||||
void open(VFS::Node* node, bool can_read);
|
||||
void open(VFS::Node* node, bool can_read, bool can_write);
|
||||
|
||||
Descriptor(const Descriptor& other);
|
||||
Descriptor();
|
||||
@ -29,6 +35,7 @@ struct Descriptor
|
||||
private:
|
||||
bool m_is_open;
|
||||
bool m_can_read;
|
||||
bool m_can_write;
|
||||
VFS::Node* m_node;
|
||||
uint64_t m_offset;
|
||||
};
|
@ -14,6 +14,7 @@ namespace VFS
|
||||
struct Node;
|
||||
|
||||
typedef ssize_t (*node_read)(Node*, size_t, size_t, char*);
|
||||
typedef ssize_t (*node_write)(Node*, size_t, size_t, const char*);
|
||||
typedef Node* (*node_finddir)(Node*, const char*);
|
||||
typedef int (*node_mkdir)(Node*, const char*);
|
||||
|
||||
@ -27,10 +28,12 @@ namespace VFS
|
||||
node_read read_func;
|
||||
node_finddir find_func;
|
||||
node_mkdir mkdir_func;
|
||||
node_write write_func;
|
||||
Node* link;
|
||||
};
|
||||
|
||||
ssize_t read(Node* node, size_t offset, size_t length, char* buffer);
|
||||
ssize_t write(Node* node, size_t offset, size_t length, const char* buffer);
|
||||
int mkdir(const char* path, const char* name); // FIXME: Support deducing this via a single path.
|
||||
|
||||
void mount_root(Node* root);
|
||||
|
9
kernel/include/fs/devices/Console.h
Normal file
9
kernel/include/fs/devices/Console.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
|
||||
namespace ConsoleDevice
|
||||
{
|
||||
VFS::Node* create_new();
|
||||
|
||||
ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer);
|
||||
}
|
@ -24,7 +24,7 @@ namespace Syscall
|
||||
void sys_exit(Context* context, int status);
|
||||
void sys_yield(Context* context);
|
||||
void sys_sleep(Context* context, uint64_t ms);
|
||||
void sys_write(Context* context, const char* addr, size_t size);
|
||||
void sys_write(Context* context, int fd, size_t size, const char* addr);
|
||||
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col);
|
||||
void sys_rand(Context* context);
|
||||
void sys_getversion(Context* context, char* buffer, size_t max);
|
||||
|
@ -5,13 +5,15 @@ 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)
|
||||
: m_is_open(other.m_is_open), m_can_read(other.m_can_read), m_can_write(other.m_can_write), m_node(other.m_node),
|
||||
m_offset(other.m_offset)
|
||||
{
|
||||
}
|
||||
|
||||
void Descriptor::open(VFS::Node* node, bool can_read)
|
||||
void Descriptor::open(VFS::Node* node, bool can_read, bool can_write)
|
||||
{
|
||||
m_can_read = can_read;
|
||||
m_can_write = can_write;
|
||||
m_node = node;
|
||||
m_offset = 0;
|
||||
m_is_open = true;
|
||||
@ -22,4 +24,11 @@ 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;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::write(size_t size, const char* buffer)
|
||||
{
|
||||
ssize_t result = VFS::write(m_node, m_offset, size, buffer);
|
||||
m_offset += result;
|
||||
return result;
|
||||
}
|
@ -26,12 +26,30 @@ ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer)
|
||||
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);
|
||||
}
|
||||
|
||||
ssize_t VFS::write(Node* node, size_t offset, size_t length, const char* buffer)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
kwarnln("write() failed: trying to write to nullptr");
|
||||
return -1;
|
||||
}
|
||||
if (node->type == VFS_DIRECTORY)
|
||||
{
|
||||
kwarnln("write() failed: is a directory");
|
||||
return -EISDIR;
|
||||
}
|
||||
if (!node->write_func)
|
||||
{
|
||||
kwarnln("write() failed: the chosen node doesn't support writing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return node->write_func(node, offset, length, buffer);
|
||||
}
|
||||
|
||||
void VFS::mount_root(Node* root)
|
||||
{
|
||||
if (!root)
|
||||
@ -92,15 +110,12 @@ VFS::Node* VFS::resolve_path(const char* filename, Node* root)
|
||||
}
|
||||
if (child->flags & VFS_MOUNTPOINT)
|
||||
{
|
||||
kdbgln("Current node (%s, inode=%ld) is a mountpoint, resolving actual node", child->name,
|
||||
child->inode);
|
||||
if (!child->link)
|
||||
{
|
||||
kwarnln("Current node's link is null");
|
||||
return 0;
|
||||
}
|
||||
child = child->link;
|
||||
kdbgln("Resolved to %s (inode %ld)", child->name, child->inode);
|
||||
}
|
||||
current_node = child;
|
||||
kfree(buffer);
|
||||
|
25
kernel/src/fs/devices/Console.cpp
Normal file
25
kernel/src/fs/devices/Console.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "fs/devices/Console.h"
|
||||
#include "config.h"
|
||||
#include "render/TextRenderer.h"
|
||||
#include "std/stdio.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
|
||||
VFS::Node* ConsoleDevice::create_new()
|
||||
{
|
||||
VFS::Node* dev = new VFS::Node;
|
||||
dev->write_func = ConsoleDevice::write;
|
||||
dev->inode = 0;
|
||||
dev->length = 0;
|
||||
dev->type = VFS_FILE;
|
||||
dev->flags = 0;
|
||||
strncpy(dev->name, "console", sizeof(dev->name));
|
||||
return dev;
|
||||
}
|
||||
|
||||
ssize_t ConsoleDevice::write(VFS::Node* node, size_t, size_t size, const char* buffer)
|
||||
{
|
||||
if (!node) return -1;
|
||||
TextRenderer::write(buffer, size);
|
||||
return (ssize_t)size;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include "fs/devices/DeviceFS.h"
|
||||
#include "fs/devices/Console.h"
|
||||
#include "fs/devices/Version.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
@ -21,6 +22,7 @@ VFS::Node* DeviceFS::get()
|
||||
strncpy(devfs_root->name, "dev", sizeof(devfs_root->name));
|
||||
|
||||
devfs_files[devfs_file_count++] = VersionDevice::create_new();
|
||||
devfs_files[devfs_file_count++] = ConsoleDevice::create_new();
|
||||
return devfs_root;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ VFS::Node* VersionDevice::create_new()
|
||||
dev->inode = 0;
|
||||
dev->length = strlen(moon_version()) + 5;
|
||||
dev->type = VFS_FILE;
|
||||
dev->flags = 0;
|
||||
strncpy(dev->name, "version", sizeof(dev->name));
|
||||
return dev;
|
||||
}
|
||||
@ -20,7 +21,6 @@ ssize_t VersionDevice::read(VFS::Node* node, size_t offset, size_t size, char* b
|
||||
if (!node) return -1;
|
||||
if (offset > node->length) return -1;
|
||||
if (offset + size > node->length) { size = node->length - offset; }
|
||||
if (offset > 0) return -1;
|
||||
snprintf(buffer, size + 1, "moon %s", moon_version()); // FIXME: Support offseting this read
|
||||
return (ssize_t)size;
|
||||
}
|
@ -18,7 +18,7 @@ void Syscall::entry(Context* context)
|
||||
sys_sleep(context, context->rdi);
|
||||
break;
|
||||
case SYS_write: // sys_write
|
||||
sys_write(context, (const char*)context->rdi, context->rsi);
|
||||
sys_write(context, (int)context->rdi, context->rsi, (const char*)context->rdx);
|
||||
break;
|
||||
case SYS_paint: sys_paint(context, context->rdi, context->rsi, context->rdx, context->r10, context->r8); break;
|
||||
case SYS_rand: sys_rand(context); break;
|
||||
|
@ -8,12 +8,44 @@
|
||||
#include "thread/Scheduler.h"
|
||||
#include "thread/Task.h"
|
||||
|
||||
#define OPEN_READ 1
|
||||
#define OPEN_WRITE 2
|
||||
|
||||
#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, int fd, size_t size, const char* addr)
|
||||
{
|
||||
context->rax = size;
|
||||
TextRenderer::write(addr, size);
|
||||
if (!addr)
|
||||
{
|
||||
STDIO_FAIL(write, EINVAL);
|
||||
context->rax = -EINVAL; // FIXME: This should probably return EFAULT.
|
||||
return;
|
||||
}
|
||||
if (fd >= TASK_MAX_FDS || fd < 0)
|
||||
{
|
||||
kwarnln("file descriptor %d is outside the valid range", fd);
|
||||
STDIO_FAIL(write, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
Task* current_task = Scheduler::current_task();
|
||||
if (!current_task->files[fd].is_open())
|
||||
{
|
||||
kwarnln("file descriptor %d is not open", fd);
|
||||
STDIO_FAIL(write, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
if (!current_task->files[fd].can_write())
|
||||
{
|
||||
kwarnln("file descriptor %d is not open for writing", fd);
|
||||
STDIO_FAIL(write, EBADF);
|
||||
context->rax = -EBADF;
|
||||
return;
|
||||
}
|
||||
ssize_t result = current_task->files[fd].write(size, addr);
|
||||
context->rax = (size_t)result;
|
||||
return;
|
||||
}
|
||||
|
||||
void sys_open(Context* context, const char* filename, int flags)
|
||||
@ -24,12 +56,14 @@ void sys_open(Context* context, const char* filename, int flags)
|
||||
{
|
||||
if (!current_task->files[fd].is_open()) break;
|
||||
}
|
||||
|
||||
if (fd == TASK_MAX_FDS)
|
||||
{
|
||||
STDIO_FAIL(open, EMFILE);
|
||||
context->rax = -EMFILE;
|
||||
return;
|
||||
}
|
||||
|
||||
VFS::Node* node = VFS::resolve_path(filename);
|
||||
if (!node)
|
||||
{
|
||||
@ -37,9 +71,23 @@ void sys_open(Context* context, const char* filename, int flags)
|
||||
context->rax = -ENOENT;
|
||||
return;
|
||||
}
|
||||
kdbgln("open(): opening %s, allocated file descriptor %d", filename, fd);
|
||||
current_task->files[fd].open(node,
|
||||
(bool)flags); // FIXME: Implement more flags. (right now, 1 is can_read, 0 is not)
|
||||
|
||||
bool can_read = (flags & OPEN_READ) > 0;
|
||||
bool can_write = (flags & OPEN_WRITE) > 0;
|
||||
if (!can_read && !can_write)
|
||||
{
|
||||
STDIO_FAIL(open, EINVAL);
|
||||
context->rax = -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
kdbgln("open(): opening %s %s, allocated file descriptor %d", filename,
|
||||
(can_read && can_write) ? "rw"
|
||||
: can_read ? "r-"
|
||||
: "-w",
|
||||
fd);
|
||||
|
||||
current_task->files[fd].open(node, can_read, can_write);
|
||||
context->rax = fd;
|
||||
return;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ section .text
|
||||
extern _init
|
||||
extern main
|
||||
extern _fini
|
||||
extern initialize_libc
|
||||
extern exit
|
||||
|
||||
global _start
|
||||
@ -13,6 +14,8 @@ _start:
|
||||
push rbp ; rbp=0
|
||||
mov rbp, rsp
|
||||
|
||||
call initialize_libc
|
||||
|
||||
call _init
|
||||
|
||||
mov rdi, 0 ; argc = 0
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define _FCNTL_H
|
||||
|
||||
#define O_RDONLY 1
|
||||
#define O_WRONLY 2
|
||||
#define O_RDWR 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
@ -13,13 +13,15 @@ typedef struct
|
||||
int f_err;
|
||||
} FILE;
|
||||
|
||||
extern FILE* __stderr;
|
||||
extern FILE* __stdout;
|
||||
#define stderr __stderr
|
||||
#define stdout __stdout
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern FILE* stderr;
|
||||
#define stderr stderr
|
||||
int fclose(FILE*);
|
||||
int fflush(FILE*);
|
||||
FILE* fopen(const char*, const char*);
|
||||
|
@ -16,6 +16,7 @@ extern "C"
|
||||
unsigned int sleep(unsigned int);
|
||||
|
||||
ssize_t read(int, void*, size_t);
|
||||
ssize_t write(int, const void*, size_t);
|
||||
int close(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -5,6 +5,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
FILE* __stderr;
|
||||
FILE* __stdout;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int fclose(FILE* stream)
|
||||
@ -29,7 +32,7 @@ extern "C"
|
||||
|
||||
FILE* fopen(const char* pathname, const char*)
|
||||
{
|
||||
int fd = open(pathname, O_RDONLY); // FIXME: Use the mode string.
|
||||
int fd = open(pathname, O_RDWR); // FIXME: Use the mode string.
|
||||
if (fd < 0) { return 0; }
|
||||
FILE* stream = (FILE*)malloc(sizeof(FILE));
|
||||
stream->f_fd = fd;
|
||||
@ -74,9 +77,16 @@ extern "C"
|
||||
NOT_IMPLEMENTED("ftell");
|
||||
}
|
||||
|
||||
size_t fwrite(const void*, size_t, size_t, FILE*)
|
||||
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream)
|
||||
{
|
||||
NOT_IMPLEMENTED("fwrite");
|
||||
ssize_t status = write(stream->f_fd, buf, size * nmemb);
|
||||
if (status < 0)
|
||||
{
|
||||
stream->f_err = 1;
|
||||
return 0;
|
||||
}
|
||||
if (status == 0) stream->f_eof = 1;
|
||||
return (size_t)status;
|
||||
}
|
||||
|
||||
void setbuf(FILE*, char*)
|
||||
|
14
libs/libc/src/init.cpp
Normal file
14
libs/libc/src/init.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" void initialize_libc()
|
||||
{
|
||||
__stderr = fopen("/dev/console", "rw");
|
||||
if (!stderr) exit(errno);
|
||||
__stdout = fopen("/dev/console", "rw");
|
||||
if (!stdout) exit(errno);
|
||||
clearerr(__stderr);
|
||||
clearerr(__stdout);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include <luna.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
@ -20,7 +21,7 @@ extern "C"
|
||||
|
||||
noreturn void __luna_abort(const char* message)
|
||||
{
|
||||
syscall(SYS_write, message, strlen(message));
|
||||
fwrite(message, strlen(message), 1, stdout);
|
||||
abort();
|
||||
}
|
||||
}
|
@ -306,8 +306,7 @@ extern "C"
|
||||
{
|
||||
int vprintf(const char* format, va_list ap)
|
||||
{
|
||||
return internal_printf(
|
||||
format, [](const char* s) { syscall(SYS_write, s, strlen(s)); }, -1, ap);
|
||||
return vfprintf(stdout, format, ap);
|
||||
}
|
||||
|
||||
int vsprintf(char* str, const char* format, va_list ap)
|
||||
@ -352,23 +351,23 @@ extern "C"
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vprintf(format, ap);
|
||||
int written = vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
|
||||
int fprintf(FILE*, const char* format, ...) // FIXME: Make fprintf print to the selected file instead of stdout.
|
||||
int fprintf(FILE* stream, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int written = vprintf(format, ap);
|
||||
int written = vfprintf(stream, format, ap);
|
||||
va_end(ap);
|
||||
return written;
|
||||
}
|
||||
|
||||
int vfprintf(FILE*, const char* format,
|
||||
va_list ap) // FIXME: Make vfprintf print to the selected file instead of stdout.
|
||||
int vfprintf(FILE* stream, const char* format, va_list ap)
|
||||
{
|
||||
return vprintf(format, ap);
|
||||
return internal_printf(
|
||||
format, [&](const char* s) { fwrite(s, strlen(s), 1, stream); }, -1, ap);
|
||||
}
|
||||
}
|
@ -10,9 +10,9 @@ extern "C"
|
||||
{
|
||||
int puts(const char* s)
|
||||
{
|
||||
long nwritten = syscall(SYS_write, s, strlen(s));
|
||||
long nwritten = fwrite(s, strlen(s), 1, stdout);
|
||||
if (nwritten < 0) return -1;
|
||||
nwritten += syscall(SYS_write, "\n", 1);
|
||||
nwritten += fwrite("\n", 1, 1, stdout);
|
||||
return (int)nwritten;
|
||||
}
|
||||
void perror(const char* s) // FIXME: Print to stderr, whenever we have an stderr.
|
||||
|
@ -37,7 +37,6 @@ extern "C"
|
||||
case SYS_exit:
|
||||
case SYS_close:
|
||||
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
|
||||
case SYS_write:
|
||||
case SYS_munmap:
|
||||
case SYS_open:
|
||||
case SYS_getversion: {
|
||||
@ -46,6 +45,7 @@ extern "C"
|
||||
result = __luna_syscall2(number, arg0, arg1);
|
||||
break;
|
||||
}
|
||||
case SYS_write:
|
||||
case SYS_read:
|
||||
case SYS_mmap: {
|
||||
arg arg0 = va_arg(ap, arg);
|
||||
@ -80,6 +80,11 @@ extern "C"
|
||||
return syscall(SYS_read, fd, count, buf); // yes, our read() syscall is in the wrong order.
|
||||
}
|
||||
|
||||
ssize_t write(int fd, const void* buf, size_t count)
|
||||
{
|
||||
return syscall(SYS_write, fd, count, buf); // yes, our read() syscall is in the wrong order.
|
||||
}
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
return (int)syscall(SYS_close, fd);
|
||||
|
Loading…
Reference in New Issue
Block a user