apio
71e15e94af
Kernel: Add an errno.h header with definitions for each header, and return those, negated, from syscalls when there is an error. mmap() returns an invalid address with errno encoded, instead of returning a negated errno; this address is encoded as ffffffffffffffEE where EE is errno in hex. libc: make syscall() return -1 and set errno on error, instead of returning the raw return value of the system call. Also, add mmap() and munmap() wrappers in sys/mman.h :). userspace: make the memeater program show the value of errno when allocating memory fails. Things to improve: add perror() and strerror() to make the errno experience even better! >.<
90 lines
2.6 KiB
C++
90 lines
2.6 KiB
C++
#define MODULE "mem"
|
|
|
|
#include "errno.h"
|
|
#include "interrupts/Context.h"
|
|
#include "log/Log.h"
|
|
#include "memory/MemoryManager.h"
|
|
#include "memory/VMM.h"
|
|
#include <stddef.h>
|
|
|
|
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
|
|
|
void sys_mmap(Context* context, void* address, size_t size, int flags)
|
|
{
|
|
if (size < 4096)
|
|
{
|
|
kdbgln("sys_mmap: size too small");
|
|
context->rax = MAP_FAIL(EINVAL);
|
|
return;
|
|
}
|
|
int real_flags = MAP_USER;
|
|
if (flags & MAP_READ_WRITE) real_flags |= MAP_READ_WRITE;
|
|
if (address)
|
|
{
|
|
kdbgln("sys_mmap: %ld pages at address %lx, %s", size / 4096, (uint64_t)address,
|
|
real_flags & MAP_READ_WRITE ? "rw" : "ro");
|
|
if (kernelVMM.getPhysical((uint64_t)address) != (uint64_t)-1) // Address is already used.
|
|
{
|
|
kdbgln("attempt to mmap an already mapped address");
|
|
context->rax = MAP_FAIL(ENOMEM);
|
|
return;
|
|
}
|
|
uint64_t offset = (uint64_t)address % 4096;
|
|
void* result = MemoryManager::get_pages_at((uint64_t)address - offset, size / 4096, real_flags);
|
|
if (result)
|
|
{
|
|
kdbgln("mmap succeeded: %lx", (uint64_t)result);
|
|
context->rax = (uint64_t)result;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
kdbgln("mmap failed");
|
|
context->rax = MAP_FAIL(ENOMEM);
|
|
return;
|
|
}
|
|
}
|
|
kdbgln("sys_mmap: %ld pages at any address, %s", size / 4096, real_flags & MAP_READ_WRITE ? "rw" : "ro");
|
|
void* result = MemoryManager::get_pages(size / 4096, real_flags);
|
|
if (result)
|
|
{
|
|
kdbgln("mmap succeeded: %lx", (uint64_t)result);
|
|
context->rax = (uint64_t)result;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
kdbgln("mmap failed");
|
|
context->rax = MAP_FAIL(ENOMEM);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void sys_munmap(Context* context, void* address, size_t size)
|
|
{
|
|
kdbgln("sys_munmap: attempting to unmap %lx", (uint64_t)address);
|
|
if (size < 4096)
|
|
{
|
|
kdbgln("munmap failed: size is too small");
|
|
context->rax = -EINVAL;
|
|
return;
|
|
}
|
|
if (!address)
|
|
{
|
|
kdbgln("munmap failed: attempted to unmap page 0");
|
|
context->rax = -EINVAL;
|
|
return;
|
|
}
|
|
uint64_t flags = kernelVMM.getFlags((uint64_t)address);
|
|
if (!(flags & MAP_USER))
|
|
{
|
|
kdbgln("munmap failed: attempted to unmap a kernel page");
|
|
context->rax = -EINVAL;
|
|
return;
|
|
}
|
|
uint64_t offset = (uint64_t)address % 4096;
|
|
MemoryManager::release_pages((void*)((uint64_t)address - offset), size / 4096);
|
|
kdbgln("munmap succeeded");
|
|
context->rax = 0;
|
|
return;
|
|
} |