Kernel: Implement mmap-able device files (regular files are not mmap-able yet)

This commit is contained in:
apio 2022-11-02 20:24:07 +01:00
parent 42a805fd60
commit 8f2308c80d
14 changed files with 130 additions and 12 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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