syscall: add lots of syscalls
This commit is contained in:
30
syscall/config.c
Normal file
30
syscall/config.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include <kernel/sched.h>
|
||||||
|
#include <kernel/syscall.h>
|
||||||
|
#include <kernel/vm-region.h>
|
||||||
|
|
||||||
|
kern_status_t sys_kern_config_get(kern_config_key_t key, void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case KERN_CFG_PAGE_SIZE:
|
||||||
|
if (!validate_access_w(self, ptr, sizeof(uintptr_t))) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(uint32_t *)ptr = VM_PAGE_SIZE;
|
||||||
|
return KERN_OK;
|
||||||
|
default:
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERN_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_kern_config_set(
|
||||||
|
kern_config_key_t key,
|
||||||
|
const void *ptr,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
return KERN_ACCESS_DENIED;
|
||||||
|
}
|
||||||
@@ -5,8 +5,36 @@
|
|||||||
#define SYSCALL_TABLE_ENTRY(id, p) [SYS_##id] = (virt_addr_t)(sys_##p)
|
#define SYSCALL_TABLE_ENTRY(id, p) [SYS_##id] = (virt_addr_t)(sys_##p)
|
||||||
|
|
||||||
static const virt_addr_t syscall_table[] = {
|
static const virt_addr_t syscall_table[] = {
|
||||||
SYSCALL_TABLE_ENTRY(EXIT, exit),
|
SYSCALL_TABLE_ENTRY(TASK_EXIT, task_exit),
|
||||||
|
SYSCALL_TABLE_ENTRY(TASK_CREATE, task_create),
|
||||||
|
SYSCALL_TABLE_ENTRY(TASK_CREATE_THREAD, task_create_thread),
|
||||||
|
SYSCALL_TABLE_ENTRY(THREAD_START, thread_start),
|
||||||
SYSCALL_TABLE_ENTRY(VM_OBJECT_CREATE, vm_object_create),
|
SYSCALL_TABLE_ENTRY(VM_OBJECT_CREATE, vm_object_create),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_OBJECT_READ, vm_object_read),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_OBJECT_WRITE, vm_object_write),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_OBJECT_COPY, vm_object_copy),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_REGION_CREATE, vm_region_create),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_REGION_READ, vm_region_read),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_REGION_WRITE, vm_region_write),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_REGION_MAP_ABSOLUTE, vm_region_map_absolute),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_REGION_MAP_RELATIVE, vm_region_map_relative),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_REGION_UNMAP_ABSOLUTE, vm_region_unmap_absolute),
|
||||||
|
SYSCALL_TABLE_ENTRY(VM_REGION_UNMAP_RELATIVE, vm_region_unmap_relative),
|
||||||
|
SYSCALL_TABLE_ENTRY(KERN_LOG, kern_log),
|
||||||
|
SYSCALL_TABLE_ENTRY(KERN_HANDLE_CLOSE, kern_handle_close),
|
||||||
|
SYSCALL_TABLE_ENTRY(KERN_CONFIG_GET, kern_config_get),
|
||||||
|
SYSCALL_TABLE_ENTRY(KERN_CONFIG_SET, kern_config_set),
|
||||||
|
SYSCALL_TABLE_ENTRY(CHANNEL_CREATE, channel_create),
|
||||||
|
SYSCALL_TABLE_ENTRY(PORT_CREATE, port_create),
|
||||||
|
SYSCALL_TABLE_ENTRY(PORT_CONNECT, port_connect),
|
||||||
|
SYSCALL_TABLE_ENTRY(PORT_DISCONNECT, port_disconnect),
|
||||||
|
SYSCALL_TABLE_ENTRY(MSG_SEND, msg_send),
|
||||||
|
SYSCALL_TABLE_ENTRY(MSG_RECV, msg_recv),
|
||||||
|
SYSCALL_TABLE_ENTRY(MSG_REPLY, msg_reply),
|
||||||
|
SYSCALL_TABLE_ENTRY(MSG_READ, msg_read),
|
||||||
|
SYSCALL_TABLE_ENTRY(MSG_READ_HANDLES, msg_read_handles),
|
||||||
|
SYSCALL_TABLE_ENTRY(MSG_WRITE, msg_write),
|
||||||
|
SYSCALL_TABLE_ENTRY(MSG_WRITE_HANDLES, msg_write_handles),
|
||||||
};
|
};
|
||||||
static const size_t syscall_table_count
|
static const size_t syscall_table_count
|
||||||
= sizeof syscall_table / sizeof syscall_table[0];
|
= sizeof syscall_table / sizeof syscall_table[0];
|
||||||
|
|||||||
8
syscall/handle.c
Normal file
8
syscall/handle.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <kernel/sched.h>
|
||||||
|
#include <kernel/syscall.h>
|
||||||
|
|
||||||
|
kern_status_t sys_kern_handle_close(kern_handle_t handle)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
return task_close_handle(self, handle);
|
||||||
|
}
|
||||||
9
syscall/log.c
Normal file
9
syscall/log.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include <kernel/printk.h>
|
||||||
|
#include <kernel/sched.h>
|
||||||
|
|
||||||
|
kern_status_t sys_kern_log(const char *s)
|
||||||
|
{
|
||||||
|
struct task *task = current_task();
|
||||||
|
printk("%s: %s", task->t_name, s);
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
196
syscall/msg.c
Normal file
196
syscall/msg.c
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
#include <kernel/channel.h>
|
||||||
|
#include <kernel/port.h>
|
||||||
|
#include <kernel/printk.h>
|
||||||
|
#include <kernel/sched.h>
|
||||||
|
#include <kernel/syscall.h>
|
||||||
|
#include <kernel/vm-region.h>
|
||||||
|
|
||||||
|
kern_status_t sys_channel_create(
|
||||||
|
unsigned int id,
|
||||||
|
channel_flags_t flags,
|
||||||
|
kern_handle_t *out)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
if (!validate_access_w(self, out, sizeof *out)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct channel *channel = channel_create();
|
||||||
|
if (!channel) {
|
||||||
|
return KERN_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long irq_flags;
|
||||||
|
task_lock_irqsave(self, &irq_flags);
|
||||||
|
|
||||||
|
if (task_get_channel(self, id)) {
|
||||||
|
task_unlock_irqrestore(self, irq_flags);
|
||||||
|
return KERN_NAME_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_handle_t handle;
|
||||||
|
kern_status_t status
|
||||||
|
= task_open_handle(self, &channel->c_base, 0, &handle);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, irq_flags);
|
||||||
|
object_unref(&channel->c_base);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_add_channel(self, channel, id);
|
||||||
|
task_unlock_irqrestore(self, irq_flags);
|
||||||
|
|
||||||
|
*out = handle;
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_port_create(kern_handle_t *out)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
if (!validate_access_w(self, out, sizeof *out)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct port *port = port_create();
|
||||||
|
if (!port) {
|
||||||
|
return KERN_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long irq_flags;
|
||||||
|
task_lock_irqsave(self, &irq_flags);
|
||||||
|
|
||||||
|
kern_handle_t handle;
|
||||||
|
kern_status_t status
|
||||||
|
= task_open_handle(self, &port->p_base, 0, &handle);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, irq_flags);
|
||||||
|
object_unref(&port->p_base);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_unlock_irqrestore(self, irq_flags);
|
||||||
|
|
||||||
|
*out = handle;
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_port_connect(
|
||||||
|
kern_handle_t port_handle,
|
||||||
|
tid_t task_id,
|
||||||
|
unsigned int channel_id)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
struct task *self = current_task();
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *port_obj = NULL;
|
||||||
|
handle_flags_t port_handle_flags = 0;
|
||||||
|
kern_status_t status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
port_handle,
|
||||||
|
&port_obj,
|
||||||
|
&port_handle_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add a reference to the port object to make sure it isn't deleted
|
||||||
|
* while we're using it */
|
||||||
|
object_ref(port_obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
struct task *remote_task = task_from_tid(task_id);
|
||||||
|
if (!remote_task) {
|
||||||
|
return KERN_NO_ENTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_lock_irqsave(remote_task, &flags);
|
||||||
|
|
||||||
|
struct channel *remote = task_get_channel(remote_task, channel_id);
|
||||||
|
if (!remote) {
|
||||||
|
task_unlock_irqrestore(remote_task, flags);
|
||||||
|
return KERN_NO_ENTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(&remote->c_base);
|
||||||
|
task_unlock_irqrestore(remote_task, flags);
|
||||||
|
|
||||||
|
status = port_connect(port_cast(port_obj), remote);
|
||||||
|
object_unref(port_obj);
|
||||||
|
object_unref(&remote->c_base);
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_port_disconnect(kern_handle_t port)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_msg_send(
|
||||||
|
kern_handle_t port,
|
||||||
|
msg_flags_t flags,
|
||||||
|
const struct msg *req,
|
||||||
|
struct msg *resp)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_msg_recv(
|
||||||
|
kern_handle_t channel,
|
||||||
|
msg_flags_t flags,
|
||||||
|
msgid_t *out_id,
|
||||||
|
struct msg *out_msg)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_msg_reply(
|
||||||
|
kern_handle_t channel,
|
||||||
|
msg_flags_t flags,
|
||||||
|
msgid_t id,
|
||||||
|
const struct msg *reply)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_msg_read(
|
||||||
|
kern_handle_t channel,
|
||||||
|
msgid_t id,
|
||||||
|
size_t offset,
|
||||||
|
struct iovec *out,
|
||||||
|
size_t nr_out)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_msg_read_handles(
|
||||||
|
kern_handle_t channel,
|
||||||
|
msgid_t id,
|
||||||
|
size_t offset,
|
||||||
|
struct handle_list *out,
|
||||||
|
size_t nr_out)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_msg_write(
|
||||||
|
kern_handle_t channel,
|
||||||
|
msgid_t id,
|
||||||
|
size_t offset,
|
||||||
|
const struct iovec *in,
|
||||||
|
size_t nr_in)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_msg_write_handles(
|
||||||
|
kern_handle_t channel,
|
||||||
|
msgid_t id,
|
||||||
|
size_t offset,
|
||||||
|
const struct handle_list *in,
|
||||||
|
size_t nr_in)
|
||||||
|
{
|
||||||
|
return KERN_UNIMPLEMENTED;
|
||||||
|
}
|
||||||
202
syscall/task.c
202
syscall/task.c
@@ -1,13 +1,203 @@
|
|||||||
#include <mango/machine/cpu.h>
|
#include <kernel/machine/cpu.h>
|
||||||
#include <mango/printk.h>
|
#include <kernel/printk.h>
|
||||||
#include <mango/sched.h>
|
#include <kernel/sched.h>
|
||||||
|
#include <kernel/syscall.h>
|
||||||
|
#include <kernel/vm-region.h>
|
||||||
|
|
||||||
extern kern_status_t sys_exit(int status)
|
extern kern_status_t sys_task_exit(int status)
|
||||||
{
|
{
|
||||||
printk("sys_exit(%d)", status);
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ml_cpu_pause();
|
printk("sys_exit(%d)", status);
|
||||||
|
milli_sleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return KERN_UNIMPLEMENTED;
|
return KERN_UNIMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_task_create(
|
||||||
|
kern_handle_t parent_handle,
|
||||||
|
const char *name,
|
||||||
|
size_t name_len,
|
||||||
|
kern_handle_t *out_task,
|
||||||
|
kern_handle_t *out_address_space)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (name_len && !validate_access_r(self, name, name_len)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_access_w(self, out_task, sizeof *out_task)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_access_w(
|
||||||
|
self,
|
||||||
|
out_address_space,
|
||||||
|
sizeof *out_address_space)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct object *parent_obj;
|
||||||
|
handle_flags_t parent_flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
kern_status_t status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
parent_handle,
|
||||||
|
&parent_obj,
|
||||||
|
&parent_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(parent_obj);
|
||||||
|
struct task *parent = task_cast(parent_obj);
|
||||||
|
|
||||||
|
struct handle *child_handle_slot = NULL, *space_handle_slot = NULL;
|
||||||
|
kern_handle_t child_handle, space_handle;
|
||||||
|
status = handle_table_alloc_handle(
|
||||||
|
self->t_handles,
|
||||||
|
&child_handle_slot,
|
||||||
|
&child_handle);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = handle_table_alloc_handle(
|
||||||
|
self->t_handles,
|
||||||
|
&space_handle_slot,
|
||||||
|
&space_handle);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
handle_table_free_handle(self->t_handles, child_handle);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
struct task *child = task_create(name, name_len);
|
||||||
|
if (!child) {
|
||||||
|
object_unref(parent_obj);
|
||||||
|
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
handle_table_free_handle(self->t_handles, child_handle);
|
||||||
|
handle_table_free_handle(self->t_handles, space_handle);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
return KERN_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_lock_irqsave(parent, &flags);
|
||||||
|
task_add_child(parent, child);
|
||||||
|
task_unlock_irqrestore(parent, flags);
|
||||||
|
|
||||||
|
child_handle_slot->h_object = &child->t_base;
|
||||||
|
space_handle_slot->h_object = &child->t_address_space->vr_base;
|
||||||
|
|
||||||
|
object_add_handle(&child->t_base);
|
||||||
|
object_add_handle(&child->t_address_space->vr_base);
|
||||||
|
|
||||||
|
object_unref(parent_obj);
|
||||||
|
|
||||||
|
*out_task = child_handle;
|
||||||
|
*out_address_space = space_handle;
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_task_create_thread(
|
||||||
|
kern_handle_t task,
|
||||||
|
virt_addr_t ip,
|
||||||
|
virt_addr_t sp,
|
||||||
|
uintptr_t *args,
|
||||||
|
size_t nr_args,
|
||||||
|
kern_handle_t *out_thread)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (!validate_access_r(self, args, nr_args * sizeof(uintptr_t))) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_access_w(self, out_thread, sizeof *out_thread)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct object *target_obj;
|
||||||
|
handle_flags_t target_flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
kern_status_t status
|
||||||
|
= task_resolve_handle(self, task, &target_obj, &target_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(target_obj);
|
||||||
|
struct task *target = task_cast(target_obj);
|
||||||
|
|
||||||
|
struct handle *target_handle = NULL;
|
||||||
|
kern_handle_t out_handle;
|
||||||
|
status = handle_table_alloc_handle(
|
||||||
|
self->t_handles,
|
||||||
|
&target_handle,
|
||||||
|
&out_handle);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
task_lock_irqsave(target, &flags);
|
||||||
|
|
||||||
|
struct thread *thread = task_create_thread(target);
|
||||||
|
if (!thread) {
|
||||||
|
object_unref(target_obj);
|
||||||
|
task_unlock_irqrestore(target, flags);
|
||||||
|
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
handle_table_free_handle(self->t_handles, out_handle);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_init_user(thread, ip, sp, args, nr_args);
|
||||||
|
target_handle->h_object = &thread->thr_base;
|
||||||
|
object_add_handle(&thread->thr_base);
|
||||||
|
|
||||||
|
task_unlock_irqrestore(target, flags);
|
||||||
|
|
||||||
|
*out_thread = out_handle;
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_thread_start(kern_handle_t thread_handle)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
struct object *thread_obj;
|
||||||
|
handle_flags_t thread_flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
kern_status_t status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
thread_handle,
|
||||||
|
&thread_obj,
|
||||||
|
&thread_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(thread_obj);
|
||||||
|
struct thread *thread = thread_cast(thread_obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
schedule_thread_on_cpu(thread);
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,165 @@
|
|||||||
#include <mango/handle.h>
|
#include <kernel/handle.h>
|
||||||
#include <mango/printk.h>
|
#include <kernel/printk.h>
|
||||||
#include <mango/vm-region.h>
|
#include <kernel/sched.h>
|
||||||
|
#include <kernel/syscall.h>
|
||||||
|
#include <kernel/vm-object.h>
|
||||||
|
#include <kernel/vm-region.h>
|
||||||
|
|
||||||
kern_status_t sys_vm_object_create(
|
kern_status_t sys_vm_object_create(
|
||||||
const char *name,
|
const char *name,
|
||||||
size_t len,
|
size_t name_len,
|
||||||
enum vm_prot prot,
|
size_t data_len,
|
||||||
|
vm_prot_t prot,
|
||||||
kern_handle_t *out_handle)
|
kern_handle_t *out_handle)
|
||||||
{
|
{
|
||||||
printk("sys_vm_object_create()");
|
struct task *self = current_task();
|
||||||
return KERN_UNIMPLEMENTED;
|
|
||||||
|
if ((name || name_len) && !validate_access_r(self, name, name_len)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_access_w(self, out_handle, sizeof *out_handle)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_object *obj
|
||||||
|
= vm_object_create(name, name_len, data_len, prot);
|
||||||
|
if (!obj) {
|
||||||
|
return KERN_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t status
|
||||||
|
= task_open_handle(self, &obj->vo_base, 0, out_handle);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
object_unref(&obj->vo_base);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_object_read(
|
||||||
|
kern_handle_t object,
|
||||||
|
void *dst,
|
||||||
|
off_t offset,
|
||||||
|
size_t count,
|
||||||
|
size_t *nr_read)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (!validate_access_w(self, dst, count)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_read && !validate_access_w(self, nr_read, sizeof *nr_read)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct object *obj = NULL;
|
||||||
|
handle_flags_t flags = 0;
|
||||||
|
kern_status_t status = task_resolve_handle(self, object, &obj, &flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_object *vmo = vm_object_cast(obj);
|
||||||
|
if (!vmo) {
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm_object_read(vmo, dst, offset, count, nr_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_object_write(
|
||||||
|
kern_handle_t object,
|
||||||
|
const void *src,
|
||||||
|
off_t offset,
|
||||||
|
size_t count,
|
||||||
|
size_t *nr_written)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (!validate_access_r(self, src, count)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_written
|
||||||
|
&& !validate_access_w(self, nr_written, sizeof *nr_written)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct object *obj = NULL;
|
||||||
|
handle_flags_t flags = 0;
|
||||||
|
kern_status_t status = task_resolve_handle(self, object, &obj, &flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_object *vmo = vm_object_cast(obj);
|
||||||
|
if (!vmo) {
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm_object_write(vmo, src, offset, count, nr_written);
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_object_copy(
|
||||||
|
kern_handle_t dst,
|
||||||
|
off_t dst_offset,
|
||||||
|
kern_handle_t src,
|
||||||
|
off_t src_offset,
|
||||||
|
size_t count,
|
||||||
|
size_t *nr_copied)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (nr_copied
|
||||||
|
&& !validate_access_w(self, nr_copied, sizeof *nr_copied)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
kern_status_t status;
|
||||||
|
struct object *dst_obj = NULL, *src_obj = NULL;
|
||||||
|
handle_flags_t dst_flags = 0, src_flags = 0;
|
||||||
|
|
||||||
|
status = task_resolve_handle(self, dst, &dst_obj, &dst_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = task_resolve_handle(self, src, &src_obj, &src_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(src_obj);
|
||||||
|
object_ref(dst_obj);
|
||||||
|
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
struct vm_object *dst_vmo = vm_object_cast(dst_obj);
|
||||||
|
struct vm_object *src_vmo = vm_object_cast(src_obj);
|
||||||
|
if (!dst_vmo || !src_vmo) {
|
||||||
|
object_unref(src_obj);
|
||||||
|
object_unref(dst_obj);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = vm_object_copy(
|
||||||
|
dst_vmo,
|
||||||
|
dst_offset,
|
||||||
|
src_vmo,
|
||||||
|
src_offset,
|
||||||
|
count,
|
||||||
|
nr_copied);
|
||||||
|
|
||||||
|
object_unref(src_obj);
|
||||||
|
object_unref(dst_obj);
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
434
syscall/vm-region.c
Normal file
434
syscall/vm-region.c
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
#include <kernel/printk.h>
|
||||||
|
#include <kernel/sched.h>
|
||||||
|
#include <kernel/syscall.h>
|
||||||
|
#include <kernel/vm-object.h>
|
||||||
|
#include <kernel/vm-region.h>
|
||||||
|
|
||||||
|
kern_status_t sys_vm_region_create(
|
||||||
|
kern_handle_t parent,
|
||||||
|
const char *name,
|
||||||
|
size_t name_len,
|
||||||
|
off_t offset,
|
||||||
|
size_t region_len,
|
||||||
|
vm_prot_t prot,
|
||||||
|
kern_handle_t *out,
|
||||||
|
virt_addr_t *out_base_address)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (name_len && !validate_access_r(self, name, name_len)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_access_w(self, out, sizeof *out)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_access_w(
|
||||||
|
self,
|
||||||
|
out_base_address,
|
||||||
|
sizeof *out_base_address)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *obj = NULL;
|
||||||
|
handle_flags_t handle_flags = 0;
|
||||||
|
kern_status_t status
|
||||||
|
= task_resolve_handle(self, parent, &obj, &handle_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_region *parent_region = vm_region_cast(obj);
|
||||||
|
if (!parent_region) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct handle *child_handle_slot = NULL;
|
||||||
|
kern_handle_t child_handle = KERN_HANDLE_INVALID;
|
||||||
|
|
||||||
|
status = handle_table_alloc_handle(
|
||||||
|
self->t_handles,
|
||||||
|
&child_handle_slot,
|
||||||
|
&child_handle);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
struct vm_region *child = NULL;
|
||||||
|
status = vm_region_create(
|
||||||
|
parent_region,
|
||||||
|
name,
|
||||||
|
name_len,
|
||||||
|
offset,
|
||||||
|
region_len,
|
||||||
|
prot,
|
||||||
|
&child);
|
||||||
|
object_unref(obj);
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
handle_table_free_handle(self->t_handles, child_handle);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
child_handle_slot->h_object = &child->vr_base;
|
||||||
|
object_add_handle(&child->vr_base);
|
||||||
|
object_unref(&child->vr_base);
|
||||||
|
|
||||||
|
*out = child_handle;
|
||||||
|
*out_base_address = vm_region_get_base_address(child);
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_region_read(
|
||||||
|
kern_handle_t region_handle,
|
||||||
|
void *dst,
|
||||||
|
off_t offset,
|
||||||
|
size_t count,
|
||||||
|
size_t *nr_read)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (!validate_access_w(self, dst, count)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_read && !validate_access_w(self, nr_read, sizeof *nr_read)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *obj = NULL;
|
||||||
|
handle_flags_t handle_flags = 0;
|
||||||
|
kern_status_t status
|
||||||
|
= task_resolve_handle(self, region_handle, &obj, &handle_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_region *region = vm_region_cast(obj);
|
||||||
|
if (!region) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
virt_addr_t src_address = vm_region_get_base_address(region) + offset;
|
||||||
|
status = vm_region_memmove(
|
||||||
|
self->t_address_space,
|
||||||
|
(virt_addr_t)dst,
|
||||||
|
region,
|
||||||
|
src_address,
|
||||||
|
count,
|
||||||
|
nr_read);
|
||||||
|
object_unref(obj);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_region_write(
|
||||||
|
kern_handle_t region_handle,
|
||||||
|
const void *src,
|
||||||
|
off_t offset,
|
||||||
|
size_t count,
|
||||||
|
size_t *nr_written)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (!validate_access_r(self, src, count)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_written
|
||||||
|
&& !validate_access_w(self, nr_written, sizeof *nr_written)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *obj = NULL;
|
||||||
|
handle_flags_t handle_flags = 0;
|
||||||
|
kern_status_t status
|
||||||
|
= task_resolve_handle(self, region_handle, &obj, &handle_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_region *region = vm_region_cast(obj);
|
||||||
|
if (!region) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
virt_addr_t dst_address = vm_region_get_base_address(region) + offset;
|
||||||
|
status = vm_region_memmove(
|
||||||
|
region,
|
||||||
|
dst_address,
|
||||||
|
self->t_address_space,
|
||||||
|
(virt_addr_t)src,
|
||||||
|
count,
|
||||||
|
nr_written);
|
||||||
|
object_unref(obj);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_region_map_absolute(
|
||||||
|
kern_handle_t region_handle,
|
||||||
|
virt_addr_t map_address,
|
||||||
|
kern_handle_t object_handle,
|
||||||
|
off_t object_offset,
|
||||||
|
size_t length,
|
||||||
|
vm_prot_t prot,
|
||||||
|
virt_addr_t *out_base_address)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (out_base_address
|
||||||
|
&& !validate_access_r(
|
||||||
|
self,
|
||||||
|
out_base_address,
|
||||||
|
sizeof *out_base_address)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t status = KERN_OK;
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *region_obj = NULL, *vmo_obj = NULL;
|
||||||
|
handle_flags_t region_flags = 0, vmo_flags = 0;
|
||||||
|
status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
region_handle,
|
||||||
|
®ion_obj,
|
||||||
|
®ion_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = task_resolve_handle(self, object_handle, &vmo_obj, &vmo_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_region *region = vm_region_cast(region_obj);
|
||||||
|
if (!region) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_object *vmo = vm_object_cast(vmo_obj);
|
||||||
|
if (!vmo) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(vmo_obj);
|
||||||
|
object_ref(region_obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
off_t region_offset = VM_REGION_ANY_OFFSET;
|
||||||
|
if (map_address != VM_REGION_ANY_OFFSET) {
|
||||||
|
region_offset
|
||||||
|
= map_address - vm_region_get_base_address(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = vm_region_map_object(
|
||||||
|
region,
|
||||||
|
region_offset,
|
||||||
|
vmo,
|
||||||
|
object_offset,
|
||||||
|
length,
|
||||||
|
prot,
|
||||||
|
out_base_address);
|
||||||
|
|
||||||
|
object_unref(vmo_obj);
|
||||||
|
object_unref(region_obj);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_region_map_relative(
|
||||||
|
kern_handle_t region_handle,
|
||||||
|
off_t region_offset,
|
||||||
|
kern_handle_t object_handle,
|
||||||
|
off_t object_offset,
|
||||||
|
size_t length,
|
||||||
|
vm_prot_t prot,
|
||||||
|
virt_addr_t *out_base_address)
|
||||||
|
{
|
||||||
|
tracek("vm_region_map_relative(%x, %x, %x, %x, %x, %x, %p)",
|
||||||
|
region_handle,
|
||||||
|
region_offset,
|
||||||
|
object_handle,
|
||||||
|
object_offset,
|
||||||
|
length,
|
||||||
|
prot,
|
||||||
|
out_base_address);
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
if (out_base_address
|
||||||
|
&& !validate_access_r(
|
||||||
|
self,
|
||||||
|
out_base_address,
|
||||||
|
sizeof *out_base_address)) {
|
||||||
|
return KERN_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t status = KERN_OK;
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *region_obj = NULL, *vmo_obj = NULL;
|
||||||
|
handle_flags_t region_flags = 0, vmo_flags = 0;
|
||||||
|
status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
region_handle,
|
||||||
|
®ion_obj,
|
||||||
|
®ion_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = task_resolve_handle(self, object_handle, &vmo_obj, &vmo_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_region *region = vm_region_cast(region_obj);
|
||||||
|
if (!region) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_object *vmo = vm_object_cast(vmo_obj);
|
||||||
|
if (!vmo) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(vmo_obj);
|
||||||
|
object_ref(region_obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
status = vm_region_map_object(
|
||||||
|
region,
|
||||||
|
region_offset,
|
||||||
|
vmo,
|
||||||
|
object_offset,
|
||||||
|
length,
|
||||||
|
prot,
|
||||||
|
out_base_address);
|
||||||
|
|
||||||
|
object_unref(vmo_obj);
|
||||||
|
object_unref(region_obj);
|
||||||
|
|
||||||
|
tracek("result: %u", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_region_unmap_absolute(
|
||||||
|
kern_handle_t region_handle,
|
||||||
|
virt_addr_t address,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
kern_status_t status = KERN_OK;
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *region_obj = NULL;
|
||||||
|
handle_flags_t region_flags = 0;
|
||||||
|
status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
region_handle,
|
||||||
|
®ion_obj,
|
||||||
|
®ion_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_region *region = vm_region_cast(region_obj);
|
||||||
|
if (!region) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(region_obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
off_t region_offset = address - vm_region_get_base_address(region);
|
||||||
|
status = vm_region_unmap(region, region_offset, length);
|
||||||
|
|
||||||
|
object_unref(region_obj);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t sys_vm_region_unmap_relative(
|
||||||
|
kern_handle_t region_handle,
|
||||||
|
off_t offset,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
struct task *self = current_task();
|
||||||
|
|
||||||
|
kern_status_t status = KERN_OK;
|
||||||
|
unsigned long flags;
|
||||||
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *region_obj = NULL;
|
||||||
|
handle_flags_t region_flags = 0;
|
||||||
|
status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
region_handle,
|
||||||
|
®ion_obj,
|
||||||
|
®ion_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vm_region *region = vm_region_cast(region_obj);
|
||||||
|
if (!region) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref(region_obj);
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
status = vm_region_unmap(region, offset, length);
|
||||||
|
|
||||||
|
object_unref(region_obj);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user