Files
rosetta/lib/libc/io/unistd/mmap.c

147 lines
2.7 KiB
C
Raw Normal View History

2026-03-15 09:41:25 +00:00
#include <errno.h>
#include <mango/handle.h>
#include <mango/task.h>
#include <mango/vm.h>
#include <rosetta/fs.h>
#include <stdbool.h>
#include <sys/mman.h>
2026-03-15 09:41:25 +00:00
static vm_prot_t vm_prot_from_mmap_prot(int prot)
{
vm_prot_t vm_prot = VM_PROT_USER;
if (prot & PROT_READ) {
vm_prot |= VM_PROT_READ;
}
if (prot & PROT_WRITE) {
vm_prot |= VM_PROT_WRITE;
}
if (prot & PROT_EXEC) {
vm_prot |= VM_PROT_EXEC;
}
return vm_prot;
}
static int get_vmo_anon(
int fd,
int prot,
int flags,
size_t length,
kern_handle_t *out)
{
vm_prot_t vm_prot = vm_prot_from_mmap_prot(prot);
kern_status_t status = vm_object_create(NULL, 0, length, vm_prot, out);
return __errno_from_kern_status(status);
}
static int get_vmo(
int fd,
int prot,
int flags,
size_t length,
kern_handle_t *out)
{
if (fd == -1) {
return get_vmo_anon(fd, prot, flags, length, out);
}
int err = 0;
kern_status_t status = fs_map(fd, prot, flags, &err, out);
if (status != KERN_OK) {
return __errno_from_kern_status(status);
}
return err;
}
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
2026-03-15 09:41:25 +00:00
int tmp = 0;
if (flags & MAP_SHARED) {
tmp++;
}
if (flags & MAP_SHARED_VALIDATE) {
tmp++;
}
if (flags & MAP_PRIVATE) {
tmp++;
}
if (tmp != 1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
if ((flags & MAP_ANONYMOUS) && fd != -1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
if (!(flags & MAP_ANONYMOUS) && fd == -1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
kern_status_t status = KERN_OK;
kern_handle_t self = KERN_HANDLE_INVALID,
address_space = KERN_HANDLE_INVALID;
status = task_self(&self);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
status = task_get_address_space(self, &address_space);
kern_handle_close(self);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
kern_handle_t vmo = KERN_HANDLE_INVALID;
int err = get_vmo(fd, prot, flags, length, &vmo);
if (err != SUCCESS) {
kern_handle_close(address_space);
__set_errno(err);
return MAP_FAILED;
}
virt_addr_t map_address = 0;
vm_prot_t vm_prot = vm_prot_from_mmap_prot(prot);
if (addr && (flags & MAP_FIXED)) {
status = address_space_map(
address_space,
(virt_addr_t)addr,
vmo,
offset,
length,
vm_prot,
&map_address);
} else {
status = address_space_map(
address_space,
MAP_ADDRESS_ANY,
vmo,
offset,
length,
vm_prot,
&map_address);
}
kern_handle_close(vmo);
kern_handle_close(address_space);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
return (void *)map_address;
}