kernel: replace kern_handle_duplicate with the more powerful kern_handle_transfer
this syscall can move and copy handles within the current task, or from/to other tasks
This commit is contained in:
@@ -143,9 +143,13 @@ extern kern_status_t sys_address_space_release(
|
|||||||
|
|
||||||
extern kern_status_t sys_kern_log(const char *s);
|
extern kern_status_t sys_kern_log(const char *s);
|
||||||
extern kern_status_t sys_kern_handle_close(kern_handle_t handle);
|
extern kern_status_t sys_kern_handle_close(kern_handle_t handle);
|
||||||
extern kern_status_t sys_kern_handle_duplicate(
|
extern kern_status_t sys_kern_handle_transfer(
|
||||||
kern_handle_t handle,
|
kern_handle_t src_task_handle,
|
||||||
kern_handle_t *out);
|
kern_handle_t src_handle,
|
||||||
|
kern_handle_t dest_task_handle,
|
||||||
|
kern_handle_t dest_handle,
|
||||||
|
unsigned int mode,
|
||||||
|
kern_handle_t *out_handle);
|
||||||
extern kern_status_t sys_kern_config_get(
|
extern kern_status_t sys_kern_config_get(
|
||||||
kern_config_key_t key,
|
kern_config_key_t key,
|
||||||
void *ptr,
|
void *ptr,
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ SYSCALL_GATE address_space_release SYS_ADDRESS_SPACE_RELEASE 3
|
|||||||
|
|
||||||
SYSCALL_GATE kern_log SYS_KERN_LOG 1
|
SYSCALL_GATE kern_log SYS_KERN_LOG 1
|
||||||
SYSCALL_GATE kern_handle_close SYS_KERN_HANDLE_CLOSE 1
|
SYSCALL_GATE kern_handle_close SYS_KERN_HANDLE_CLOSE 1
|
||||||
SYSCALL_GATE kern_handle_duplicate SYS_KERN_HANDLE_DUPLICATE 2
|
SYSCALL_GATE kern_handle_transfer SYS_KERN_HANDLE_TRANSFER 6
|
||||||
SYSCALL_GATE kern_config_get SYS_KERN_CONFIG_GET 3
|
SYSCALL_GATE kern_config_get SYS_KERN_CONFIG_GET 3
|
||||||
SYSCALL_GATE kern_config_set SYS_KERN_CONFIG_SET 3
|
SYSCALL_GATE kern_config_set SYS_KERN_CONFIG_SET 3
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
#include <mango/types.h>
|
#include <mango/types.h>
|
||||||
|
|
||||||
extern kern_status_t kern_handle_close(kern_handle_t handle);
|
extern kern_status_t kern_handle_close(kern_handle_t handle);
|
||||||
extern kern_status_t kern_handle_duplicate(
|
extern kern_status_t kern_handle_transfer(
|
||||||
kern_handle_t handle,
|
kern_handle_t src_task,
|
||||||
kern_handle_t *out);
|
kern_handle_t src_handle,
|
||||||
|
kern_handle_t dest_task,
|
||||||
|
kern_handle_t dest_handle,
|
||||||
|
unsigned int mode,
|
||||||
|
kern_handle_t *out_handle);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#define SYS_KERN_LOG 1
|
#define SYS_KERN_LOG 1
|
||||||
#define SYS_KERN_HANDLE_CLOSE 2
|
#define SYS_KERN_HANDLE_CLOSE 2
|
||||||
#define SYS_KERN_HANDLE_DUPLICATE 3
|
#define SYS_KERN_HANDLE_TRANSFER 3
|
||||||
#define SYS_KERN_CONFIG_GET 4
|
#define SYS_KERN_CONFIG_GET 4
|
||||||
#define SYS_KERN_CONFIG_SET 5
|
#define SYS_KERN_CONFIG_SET 5
|
||||||
#define SYS_KERN_OBJECT_WAIT 6
|
#define SYS_KERN_OBJECT_WAIT 6
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ static const virt_addr_t syscall_table[] = {
|
|||||||
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_RELEASE, address_space_release),
|
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_RELEASE, address_space_release),
|
||||||
SYSCALL_TABLE_ENTRY(KERN_LOG, kern_log),
|
SYSCALL_TABLE_ENTRY(KERN_LOG, kern_log),
|
||||||
SYSCALL_TABLE_ENTRY(KERN_HANDLE_CLOSE, kern_handle_close),
|
SYSCALL_TABLE_ENTRY(KERN_HANDLE_CLOSE, kern_handle_close),
|
||||||
SYSCALL_TABLE_ENTRY(KERN_HANDLE_DUPLICATE, kern_handle_duplicate),
|
SYSCALL_TABLE_ENTRY(KERN_HANDLE_TRANSFER, kern_handle_transfer),
|
||||||
SYSCALL_TABLE_ENTRY(KERN_CONFIG_GET, kern_config_get),
|
SYSCALL_TABLE_ENTRY(KERN_CONFIG_GET, kern_config_get),
|
||||||
SYSCALL_TABLE_ENTRY(KERN_CONFIG_SET, kern_config_set),
|
SYSCALL_TABLE_ENTRY(KERN_CONFIG_SET, kern_config_set),
|
||||||
SYSCALL_TABLE_ENTRY(CHANNEL_CREATE, channel_create),
|
SYSCALL_TABLE_ENTRY(CHANNEL_CREATE, channel_create),
|
||||||
|
|||||||
+111
-11
@@ -8,32 +8,132 @@ kern_status_t sys_kern_handle_close(kern_handle_t handle)
|
|||||||
return task_close_handle(self, handle);
|
return task_close_handle(self, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
kern_status_t sys_kern_handle_duplicate(
|
kern_status_t sys_kern_handle_transfer(
|
||||||
kern_handle_t handle,
|
kern_handle_t src_task_handle,
|
||||||
kern_handle_t *out)
|
kern_handle_t src_handle,
|
||||||
|
kern_handle_t dest_task_handle,
|
||||||
|
kern_handle_t dest_handle,
|
||||||
|
unsigned int mode,
|
||||||
|
kern_handle_t *out_handle)
|
||||||
{
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case HANDLE_TRANSFER_MOVE:
|
||||||
|
case HANDLE_TRANSFER_COPY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
struct task *self = current_task();
|
struct task *self = current_task();
|
||||||
|
|
||||||
if (!validate_access_w(self, out, sizeof *out)) {
|
if (out_handle
|
||||||
|
&& !validate_access_w(self, out_handle, sizeof *out_handle)) {
|
||||||
return KERN_MEMORY_FAULT;
|
return KERN_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
task_lock_irqsave(self, &flags);
|
task_lock_irqsave(self, &flags);
|
||||||
|
|
||||||
|
struct object *src_object = NULL;
|
||||||
|
struct task *src_task = NULL;
|
||||||
|
struct task *dest_task = NULL;
|
||||||
|
kern_status_t status = KERN_OK;
|
||||||
|
|
||||||
struct object *obj = NULL;
|
struct object *obj = NULL;
|
||||||
handle_flags_t handle_flags = 0;
|
handle_flags_t handle_flags = 0;
|
||||||
kern_status_t status
|
|
||||||
= task_resolve_handle(self, handle, &obj, &handle_flags);
|
if (src_task_handle != KERN_HANDLE_INVALID) {
|
||||||
if (status != KERN_OK) {
|
status = task_resolve_handle(
|
||||||
task_unlock_irqrestore(self, flags);
|
self,
|
||||||
return status;
|
src_task_handle,
|
||||||
|
&obj,
|
||||||
|
&handle_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_task = task_cast(obj);
|
||||||
|
if (!src_task) {
|
||||||
|
status = KERN_INVALID_ARGUMENT;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
src_task = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = task_open_handle(self, obj, handle_flags, out);
|
if (dest_task_handle != KERN_HANDLE_INVALID) {
|
||||||
object_unref(obj);
|
status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
dest_task_handle,
|
||||||
|
&obj,
|
||||||
|
&handle_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
task_unlock_irqrestore(self, flags);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_task = task_cast(obj);
|
||||||
|
if (!dest_task) {
|
||||||
|
status = KERN_INVALID_ARGUMENT;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dest_task = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = task_resolve_handle(
|
||||||
|
self,
|
||||||
|
src_handle,
|
||||||
|
&src_object,
|
||||||
|
&handle_flags);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
task_unlock_irqrestore(self, flags);
|
task_unlock_irqrestore(self, flags);
|
||||||
|
|
||||||
|
struct handle *dest = NULL;
|
||||||
|
task_lock_irqsave(dest_task, &flags);
|
||||||
|
status = handle_table_alloc_handle(
|
||||||
|
dest_task->t_handles,
|
||||||
|
dest_handle,
|
||||||
|
&dest,
|
||||||
|
&dest_handle);
|
||||||
|
task_unlock_irqrestore(dest_task, flags);
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == HANDLE_TRANSFER_MOVE) {
|
||||||
|
object_ref(src_object);
|
||||||
|
task_lock_irqsave(src_task, &flags);
|
||||||
|
handle_table_free_handle(src_task->t_handles, src_handle);
|
||||||
|
task_unlock_irqrestore(src_task, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->h_object = src_object;
|
||||||
|
dest->h_flags = handle_flags;
|
||||||
|
|
||||||
|
if (out_handle) {
|
||||||
|
*out_handle = dest_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (src_task && src_task_handle != KERN_HANDLE_INVALID) {
|
||||||
|
object_unref(&src_task->t_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest_task && dest_task_handle != KERN_HANDLE_INVALID) {
|
||||||
|
object_unref(&dest_task->t_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_object) {
|
||||||
|
object_unref(src_object);
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user