Kernel: Implement mmap-able device files (regular files are not mmap-able yet)
This commit is contained in:
parent
42a805fd60
commit
8f2308c80d
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
11
kernel/include/fs/devices/Framebuffer.h
Normal file
11
kernel/include/fs/devices/Framebuffer.h
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
59
kernel/src/fs/devices/Framebuffer.cpp
Normal file
59
kernel/src/fs/devices/Framebuffer.cpp
Normal 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;
|
||||
}
|
@ -207,3 +207,11 @@ 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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*);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user