Compare commits

...

9 Commits

Author SHA1 Message Date
b67011c626 libc: Use the new write() syscall
The new one is write(fd, buf, count).
The old one was write(buf, count).

So the old one tries to pass buf as a file descriptor, and write() complains that 4000000 is too large of a file descriptor and throws EBADF.

We now use the new syscall, through the wrapper that fwrite() provides us.
2022-10-11 21:12:19 +02:00
0f47f59364 libc: make fprintf actually write to the chosen file
Also, printf now is kind of an alias for fprintf(stdout,...), as it should be.
2022-10-11 21:10:19 +02:00
2f46e46aa4 libc: Implement fwrite()
Now that we have the write() syscall and libc wrapper, fwrite can finally be implemented.
2022-10-11 21:09:30 +02:00
80ab982fe4 libc: make stdout and stderr functional
what were before one extern FILE* without reference now are opened by libc on program initialization, to point to /dev/console by default.
2022-10-11 21:08:46 +02:00
53a4b3b85e libc: Add new flags to open()
Since we now have write support, we can add O_WRONLY and O_RDWR to fcntl.h :)
2022-10-11 21:07:21 +02:00
12cf37d0a7 Kernel/syscalls: Modify sys_write to accept a file descriptor and write to it
Previously, sys_write only wrote to the tty. Now, it uses the VFS interface, as it should.
2022-10-11 21:06:12 +02:00
e764647133 Devices: add a new ConsoleDevice
This new device is the userspace interface to the text console/tty.
2022-10-11 21:04:50 +02:00
b1fcfd0d74 VersionDevice: Ignore offset instead of erroring out + set flags to 0 2022-10-11 21:04:14 +02:00
e67ef7778c VFS: Support writing to files 2022-10-11 21:03:30 +02:00
21 changed files with 191 additions and 36 deletions

View File

@ -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;
};

View File

@ -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);

View 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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View 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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -2,6 +2,8 @@
#define _FCNTL_H
#define O_RDONLY 1
#define O_WRONLY 2
#define O_RDWR 3
#ifdef __cplusplus
extern "C"

View File

@ -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*);

View File

@ -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

View File

@ -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
View 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);
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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);