diff --git a/kernel/include/fs/FileDescriptor.h b/kernel/include/fs/FileDescriptor.h index 482c8604..f74780ba 100644 --- a/kernel/include/fs/FileDescriptor.h +++ b/kernel/include/fs/FileDescriptor.h @@ -32,6 +32,8 @@ struct Descriptor ssize_t read(size_t size, char* buffer); ssize_t write(size_t size, const char* buffer); + uintptr_t mmap(uintptr_t addr, size_t size, int prot, off_t offset); + 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 67a63640..c1d29526 100644 --- a/kernel/include/fs/VFS.h +++ b/kernel/include/fs/VFS.h @@ -23,6 +23,7 @@ namespace VFS typedef int (*node_mkdir)(Node*, const char*, mode_t); typedef int (*node_block)(Node*); typedef Node* (*node_readdir)(Node*, long); + typedef uintptr_t (*node_mmap)(Node*, uintptr_t, size_t, int, off_t); struct Node { @@ -45,6 +46,7 @@ namespace VFS node_mkdir mkdir_func; node_write write_func; node_block block_func; + node_mmap mmap_func; Node* link; }; diff --git a/kernel/include/fs/devices/Framebuffer.h b/kernel/include/fs/devices/Framebuffer.h new file mode 100644 index 00000000..d270fd8e --- /dev/null +++ b/kernel/include/fs/devices/Framebuffer.h @@ -0,0 +1,11 @@ +#pragma once +#include "fs/VFS.h" + +namespace FramebufferDevice +{ + VFS::Node* create_new(const char* devname); + + 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); +} \ No newline at end of file diff --git a/kernel/include/memory/MemoryManager.h b/kernel/include/memory/MemoryManager.h index b509a198..cb5ece3e 100644 --- a/kernel/include/memory/MemoryManager.h +++ b/kernel/include/memory/MemoryManager.h @@ -34,4 +34,6 @@ namespace MemoryManager void release_pages(void* pages, uint64_t count); void protect(void* page, uint64_t count, int flags); + + void map_several_pages(uint64_t physicalAddress, uint64_t virtualAddress, uint64_t count, int flags = MAP_READ_WRITE); } \ No newline at end of file diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h index 94ffba07..84ffeb7d 100644 --- a/kernel/include/sys/Syscall.h +++ b/kernel/include/sys/Syscall.h @@ -48,7 +48,7 @@ void sys_sleep(Context* context, uint64_t ms); 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_getprocid(Context* context, int field); -void sys_mmap(Context* context, void* address, size_t size, int prot); +void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, off_t offset); void sys_munmap(Context* context, void* address, size_t size); void sys_open(Context* context, const char* filename, int flags, mode_t mode); void sys_read(Context* context, int fd, size_t size, char* buffer); diff --git a/kernel/src/fs/FileDescriptor.cpp b/kernel/src/fs/FileDescriptor.cpp index 59ce5da1..caa18294 100644 --- a/kernel/src/fs/FileDescriptor.cpp +++ b/kernel/src/fs/FileDescriptor.cpp @@ -37,6 +37,14 @@ ssize_t Descriptor::write(size_t size, const char* buffer) return result; } +#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) + +uintptr_t Descriptor::mmap(uintptr_t addr, size_t size, int prot, off_t offset) +{ + if(!m_node->mmap_func) return MAP_FAIL(ENOTSUP); + return m_node->mmap_func(m_node, addr, size, prot, offset); +} + int Descriptor::seek(long offset) { if (m_node->type == VFS_FILE && (uint64_t)offset > m_node->length) diff --git a/kernel/src/fs/devices/DeviceFS.cpp b/kernel/src/fs/devices/DeviceFS.cpp index a4db91e6..98de1c09 100644 --- a/kernel/src/fs/devices/DeviceFS.cpp +++ b/kernel/src/fs/devices/DeviceFS.cpp @@ -2,6 +2,7 @@ #include "fs/devices/Console.h" #include "fs/devices/Keyboard.h" #include "fs/devices/NullDevice.h" +#include "fs/devices/Framebuffer.h" #include "fs/devices/Random.h" #include "fs/devices/Serial.h" #include "fs/devices/Version.h" @@ -37,6 +38,7 @@ VFS::Node* DeviceFS::get() devfs_files[devfs_file_count++] = RandomDevice::create_new("random"); devfs_files[devfs_file_count++] = KeyboardDevice::create_new("kbd"); devfs_files[devfs_file_count++] = NullDevice::create_new("null"); + devfs_files[devfs_file_count++] = FramebufferDevice::create_new("fb0"); devfs_root->length = devfs_file_count; return devfs_root; } diff --git a/kernel/src/fs/devices/Framebuffer.cpp b/kernel/src/fs/devices/Framebuffer.cpp new file mode 100644 index 00000000..4a17b6b4 --- /dev/null +++ b/kernel/src/fs/devices/Framebuffer.cpp @@ -0,0 +1,59 @@ +#include "fs/devices/Framebuffer.h" +#include "std/stdio.h" +#include "std/stdlib.h" +#include "std/string.h" +#include "memory/MemoryManager.h" +#include "utils/Addresses.h" +#include "misc/utils.h" +#include "std/errno.h" +#include "bootboot.h" + +extern BOOTBOOT bootboot; +extern char fb[1]; + +#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) + +extern uint64_t clock_now(); + +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->inode = 0; + dev->length = 0; + dev->type = VFS_DEVICE; + dev->flags = 0; + dev->uid = dev->gid = 0; + dev->mode = 0222; + dev->atime = dev->ctime = dev->mtime = clock_now(); + strncpy(dev->name, devname, sizeof(dev->name)); + return dev; +} + +uintptr_t FramebufferDevice::mmap(VFS::Node* node, uintptr_t addr, size_t size, int prot, off_t offset) +{ + if (!node) return -1; + int real_prot = prot & ~(MAP_AS_OWNED_BY_TASK); + if(round_down_to_nearest_page(offset) != (uintptr_t)offset) + { + return MAP_FAIL(EINVAL); + } + if((size + offset) > bootboot.fb_size) + { + return MAP_FAIL(ERANGE); // FIXME: Should probably be EOVERFLOW. + } + MemoryManager::map_several_pages(bootboot.fb_ptr + offset, addr, Utilities::get_blocks_from_size(PAGE_SIZE, size), real_prot); + return addr; +} + +ssize_t FramebufferDevice::write(VFS::Node* node, size_t offset, size_t size, const char* buffer) +{ + if (!node) return -1; + if((size + offset) > (uint64_t)bootboot.fb_size) + { + size = (uint64_t)bootboot.fb_size - offset; + } + memcpy(fb + offset, buffer, size); + return (ssize_t)size; +} \ No newline at end of file diff --git a/kernel/src/memory/MemoryManager.cpp b/kernel/src/memory/MemoryManager.cpp index 10aee2df..f52d3865 100644 --- a/kernel/src/memory/MemoryManager.cpp +++ b/kernel/src/memory/MemoryManager.cpp @@ -206,4 +206,12 @@ void MemoryManager::release_pages(void* pages, uint64_t count) void MemoryManager::protect(void* page, uint64_t count, int flags) { for (uint64_t i = 0; i < count; i++) { VMM::remap((uint64_t)page + (i * PAGE_SIZE), flags); } +} + +void MemoryManager::map_several_pages(uint64_t physicalAddress, uint64_t virtualAddress, uint64_t count, int flags) +{ + for (uint64_t i = 0; i < count; i++) + { + VMM::map(virtualAddress + (i * PAGE_SIZE), physicalAddress + (i * PAGE_SIZE), flags); + } } \ No newline at end of file diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index 97cb07c2..60068b68 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -17,7 +17,7 @@ void Syscall::entry(Context* context) case SYS_write: 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_getprocid: sys_getprocid(context, (int)context->rdi); 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, (int)context->r10, (off_t)context->r8); 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, (mode_t)context->rdx); break; case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break; diff --git a/kernel/src/sys/mem.cpp b/kernel/src/sys/mem.cpp index 69c3ba59..b30261d4 100644 --- a/kernel/src/sys/mem.cpp +++ b/kernel/src/sys/mem.cpp @@ -41,7 +41,7 @@ static int mman_flags_from_prot(int prot) return flags; } -void sys_mmap(Context* context, void* address, size_t size, int prot) +void sys_mmap(Context* context, void* address, size_t size, int prot, int fd, off_t offset) { if (size < PAGE_SIZE) { @@ -58,7 +58,7 @@ void sys_mmap(Context* context, void* address, size_t size, int prot) int real_flags = mman_flags_from_prot(prot); if (address) { - kdbgln("mmap(): %ld pages at address %p, %s", size / PAGE_SIZE, address, format_prot(prot)); + kdbgln("mmap(): %ld pages at address %p, %s, fd %d", size / PAGE_SIZE, address, format_prot(prot), fd); if (Memory::is_kernel_address((uintptr_t)address)) { kwarnln("munmap() failed: attempted to unmap a kernel page"); @@ -71,8 +71,20 @@ void sys_mmap(Context* context, void* address, size_t size, int prot) context->rax = MAP_FAIL(ENOMEM); return; } - uint64_t offset = (uint64_t)address % PAGE_SIZE; - void* result = MemoryManager::get_pages_at((uint64_t)address - offset, + uint64_t addr_offset = (uint64_t)address % PAGE_SIZE; + if(fd >= 0) + { + int err; + Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err); + if(!file) + { + context->rax = MAP_FAIL(err); + return; + } + context->rax = file->mmap((uint64_t)address - addr_offset, size, real_flags, offset); + return; + } + void* result = MemoryManager::get_pages_at((uint64_t)address - addr_offset, Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags); if (result) { @@ -87,7 +99,7 @@ void sys_mmap(Context* context, void* address, size_t size, int prot) return; } } - kdbgln("mmap(): %ld pages at any address, %s", Utilities::get_blocks_from_size(PAGE_SIZE, size), format_prot(prot)); + kdbgln("mmap(): %ld pages at any address, %s, fd %d", Utilities::get_blocks_from_size(PAGE_SIZE, size), format_prot(prot), fd); uint64_t ptr = Scheduler::current_task()->allocator.request_virtual_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size)); if (!ptr) @@ -96,6 +108,18 @@ void sys_mmap(Context* context, void* address, size_t size, int prot) context->rax = MAP_FAIL(ENOMEM); return; } + if(fd >= 0) + { + int err; + Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err); + if(!file) + { + context->rax = MAP_FAIL(err); + return; + } + context->rax = file->mmap(ptr, size, real_flags, offset); + return; + } void* result = MemoryManager::get_pages_at(ptr, Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags); if (result) { diff --git a/libs/libc/src/bits/bindings.c b/libs/libc/src/bits/bindings.c index 5c58ef0b..40bdca95 100644 --- a/libs/libc/src/bits/bindings.c +++ b/libs/libc/src/bits/bindings.c @@ -13,7 +13,7 @@ int liballoc_unlock() void* liballoc_alloc(size_t size) { - void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ | PROT_WRITE, 0, 0, 0); + void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, 0, 0); if (result == MAP_FAILED) return 0; return (void*)result; } diff --git a/libs/libc/src/sys/mman.cpp b/libs/libc/src/sys/mman.cpp index ec4356f1..63017015 100644 --- a/libs/libc/src/sys/mman.cpp +++ b/libs/libc/src/sys/mman.cpp @@ -5,9 +5,9 @@ extern "C" { // FIXME: Implement a POSIX-compliant mmap. - void* mmap(void* addr, size_t len, int prot, int, int, off_t) + void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) { - long result = __luna_syscall3(SYS_mmap, (sysarg_t)addr, (sysarg_t)len, (sysarg_t)prot); + long result = __luna_syscall5(SYS_mmap, (sysarg_t)addr, (sysarg_t)len, (sysarg_t)prot, flags & MAP_ANONYMOUS ? (sysarg_t)-1 : (sysarg_t)fd, (sysarg_t)offset); _RETURN_WITH_MEMORY_ERRNO(result, void*); } diff --git a/libs/libc/src/syscall.cpp b/libs/libc/src/syscall.cpp index 42602131..f774cc4f 100644 --- a/libs/libc/src/syscall.cpp +++ b/libs/libc/src/syscall.cpp @@ -42,14 +42,14 @@ extern "C" long syscall(long number, ...) case SYS_write: case SYS_read: case SYS_mprotect: - case SYS_waitpid: - case SYS_mmap: { + case SYS_waitpid: { arg arg0 = va_arg(ap, arg); arg arg1 = va_arg(ap, arg); arg arg2 = va_arg(ap, arg); result = __luna_syscall3(number, arg0, arg1, arg2); break; } + case SYS_mmap: case SYS_paint: { arg arg0 = va_arg(ap, arg); arg arg1 = va_arg(ap, arg);