From 249c79f8a3410a1bcb55801ff31338ce1cd709f4 Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 2 Nov 2022 20:59:42 +0100 Subject: [PATCH] Kernel, libc: Add ioctl() Right now, only the framebuffer supports this system call, to query its dimensions. --- kernel/include/fs/FileDescriptor.h | 2 ++ kernel/include/fs/VFS.h | 2 ++ kernel/include/fs/devices/Framebuffer.h | 2 ++ kernel/include/sys/Syscall.h | 4 +++- kernel/src/fs/FileDescriptor.cpp | 6 ++++++ kernel/src/fs/devices/Framebuffer.cpp | 15 +++++++++++++++ kernel/src/sys/Syscall.cpp | 1 + kernel/src/sys/stdio.cpp | 20 ++++++++++++++------ libs/libc/include/sys/ioctl.h | 23 +++++++++++++++++++++++ libs/libc/include/sys/syscall.h | 1 + libs/libc/src/sys/ioctl.cpp | 17 +++++++++++++++++ libs/libc/src/syscall.cpp | 1 + 12 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 libs/libc/include/sys/ioctl.h create mode 100644 libs/libc/src/sys/ioctl.cpp diff --git a/kernel/include/fs/FileDescriptor.h b/kernel/include/fs/FileDescriptor.h index f74780ba..f5b83c23 100644 --- a/kernel/include/fs/FileDescriptor.h +++ b/kernel/include/fs/FileDescriptor.h @@ -34,6 +34,8 @@ struct Descriptor uintptr_t mmap(uintptr_t addr, size_t size, int prot, off_t offset); + long ioctl(int cmd, uintptr_t arg); + void open(VFS::Node* node, bool can_read, bool can_write, bool able_to_block, bool close_on_exec); int seek(long offset); diff --git a/kernel/include/fs/VFS.h b/kernel/include/fs/VFS.h index c1d29526..d8db1b15 100644 --- a/kernel/include/fs/VFS.h +++ b/kernel/include/fs/VFS.h @@ -24,6 +24,7 @@ namespace VFS typedef int (*node_block)(Node*); typedef Node* (*node_readdir)(Node*, long); typedef uintptr_t (*node_mmap)(Node*, uintptr_t, size_t, int, off_t); + typedef long (*node_ioctl)(Node*, int, uintptr_t); struct Node { @@ -47,6 +48,7 @@ namespace VFS node_write write_func; node_block block_func; node_mmap mmap_func; + node_ioctl ioctl_func; Node* link; }; diff --git a/kernel/include/fs/devices/Framebuffer.h b/kernel/include/fs/devices/Framebuffer.h index d270fd8e..32b2a04f 100644 --- a/kernel/include/fs/devices/Framebuffer.h +++ b/kernel/include/fs/devices/Framebuffer.h @@ -8,4 +8,6 @@ namespace FramebufferDevice ssize_t write(VFS::Node* node, size_t offset, size_t size, const char* buffer); uintptr_t mmap(VFS::Node* node, uintptr_t addr, size_t size, int prot, off_t offset); + + long ioctl(VFS::Node* node, int cmd, uintptr_t arg); } \ No newline at end of file diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h index 23a9cb4f..a24a7a8f 100644 --- a/kernel/include/sys/Syscall.h +++ b/kernel/include/sys/Syscall.h @@ -30,6 +30,7 @@ #define SYS_setuid 24 #define SYS_setgid 25 #define SYS_umask 26 +#define SYS_ioctl 27 struct stat; struct pstat; @@ -67,4 +68,5 @@ void sys_stat(Context* context, const char* path, struct stat* buf); void sys_dup2(Context* context, int fd, int fd2); void sys_setuid(Context* context, int new_uid, int new_euid); void sys_setgid(Context* context, int new_gid, int new_egid); -void sys_umask(Context* context, mode_t cmask); \ No newline at end of file +void sys_umask(Context* context, mode_t cmask); +void sys_ioctl(Context* context, int fd, int request, uintptr_t arg); \ No newline at end of file diff --git a/kernel/src/fs/FileDescriptor.cpp b/kernel/src/fs/FileDescriptor.cpp index caa18294..96266068 100644 --- a/kernel/src/fs/FileDescriptor.cpp +++ b/kernel/src/fs/FileDescriptor.cpp @@ -45,6 +45,12 @@ uintptr_t Descriptor::mmap(uintptr_t addr, size_t size, int prot, off_t offset) return m_node->mmap_func(m_node, addr, size, prot, offset); } +long Descriptor::ioctl(int cmd, uintptr_t arg) +{ + if(!m_node->ioctl_func) return MAP_FAIL(ENOTSUP); + return m_node->ioctl_func(m_node, cmd, arg); +} + int Descriptor::seek(long offset) { if (m_node->type == VFS_FILE && (uint64_t)offset > m_node->length) diff --git a/kernel/src/fs/devices/Framebuffer.cpp b/kernel/src/fs/devices/Framebuffer.cpp index 4a17b6b4..cd198508 100644 --- a/kernel/src/fs/devices/Framebuffer.cpp +++ b/kernel/src/fs/devices/Framebuffer.cpp @@ -20,6 +20,7 @@ VFS::Node* FramebufferDevice::create_new(const char* devname) VFS::Node* dev = new VFS::Node; dev->write_func = FramebufferDevice::write; dev->mmap_func = FramebufferDevice::mmap; + dev->ioctl_func = FramebufferDevice::ioctl; dev->inode = 0; dev->length = 0; dev->type = VFS_DEVICE; @@ -56,4 +57,18 @@ ssize_t FramebufferDevice::write(VFS::Node* node, size_t offset, size_t size, co } memcpy(fb + offset, buffer, size); return (ssize_t)size; +} + +#define FB_GET_WIDTH 0 +#define FB_GET_HEIGHT 1 + +long FramebufferDevice::ioctl(VFS::Node* node, int cmd, uintptr_t) +{ + if (!node) return -1; + switch(cmd) + { + case FB_GET_WIDTH: return (long)bootboot.fb_width; + case FB_GET_HEIGHT: return (long)bootboot.fb_height; + default: return -EINVAL; + } } \ No newline at end of file diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index 3b5118b8..f051a345 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -40,6 +40,7 @@ void Syscall::entry(Context* context) case SYS_setuid: sys_setuid(context, (int)context->rdi, (int)context->rsi); break; case SYS_setgid: sys_setgid(context, (int)context->rdi, (int)context->rsi); break; case SYS_umask: sys_umask(context, (mode_t)context->rdi); break; + case SYS_ioctl: sys_ioctl(context, (int)context->rdi, (int)context->rsi, (uintptr_t)context->rdx); break; default: context->rax = -ENOSYS; break; } VMM::exit_syscall_context(); diff --git a/kernel/src/sys/stdio.cpp b/kernel/src/sys/stdio.cpp index 8cc05a74..af95e628 100644 --- a/kernel/src/sys/stdio.cpp +++ b/kernel/src/sys/stdio.cpp @@ -358,12 +358,7 @@ void sys_dup2(Context* context, int fd, int fd2) context->rax = -err; return; } - if (!file1->is_open()) - { - context->rax = -EBADF; - return; - } - Descriptor* file2 = Scheduler::current_task()->descriptor_from_fd(fd2, err); + Descriptor* file2 = Scheduler::current_task()->descriptor_from_fd(fd2, err); // FIXME: This will return EBADF if fd2 is not open, but we want to replace it with fd1 if it is not open. if (!file2) { context->rax = -err; @@ -380,4 +375,17 @@ void sys_umask(Context* context, mode_t cmask) Task* current_task = Scheduler::current_task(); context->rax = current_task->umask; current_task->umask = cmask; +} + +void sys_ioctl(Context* context, int fd, int cmd, uintptr_t arg) +{ + int err; + Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err); + if (!file) + { + context->rax = -err; + return; + } + kinfoln("ioctl(): fd %d, cmd %d, arg %lu", fd, cmd, arg); + context->rax = file->ioctl(cmd, arg); } \ No newline at end of file diff --git a/libs/libc/include/sys/ioctl.h b/libs/libc/include/sys/ioctl.h new file mode 100644 index 00000000..1c1cb1e9 --- /dev/null +++ b/libs/libc/include/sys/ioctl.h @@ -0,0 +1,23 @@ +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +#include + +/* Get the width of a framebuffer device. */ +#define FB_GET_WIDTH 0 +/* Get the height of a framebuffer device. */ +#define FB_GET_HEIGHT 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Perform an arbitrary operation on an open file descriptor. Many operations are device-specific. */ + int ioctl(int fd, int cmd, ...); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libs/libc/include/sys/syscall.h b/libs/libc/include/sys/syscall.h index c50ea703..209c5d21 100644 --- a/libs/libc/include/sys/syscall.h +++ b/libs/libc/include/sys/syscall.h @@ -28,5 +28,6 @@ #define SYS_setuid 24 #define SYS_setgid 25 #define SYS_umask 26 +#define SYS_ioctl 27 #endif \ No newline at end of file diff --git a/libs/libc/src/sys/ioctl.cpp b/libs/libc/src/sys/ioctl.cpp new file mode 100644 index 00000000..29d7285c --- /dev/null +++ b/libs/libc/src/sys/ioctl.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include + +extern "C" +{ + int ioctl(int fd, int cmd, ...) + { + va_list ap; + va_start(ap, cmd); + long result = __lc_fast_syscall3(SYS_ioctl, fd, cmd, va_arg(ap, uintptr_t)); + va_end(ap); + return (int)result; + } +} \ No newline at end of file diff --git a/libs/libc/src/syscall.cpp b/libs/libc/src/syscall.cpp index 82a55e31..aad01af5 100644 --- a/libs/libc/src/syscall.cpp +++ b/libs/libc/src/syscall.cpp @@ -41,6 +41,7 @@ extern "C" long syscall(long number, ...) case SYS_seek: case SYS_write: case SYS_read: + case SYS_ioctl: case SYS_mprotect: case SYS_waitpid: { arg arg0 = va_arg(ap, arg);