147 lines
2.7 KiB
C
147 lines
2.7 KiB
C
#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>
|
|
|
|
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)
|
|
{
|
|
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;
|
|
}
|