From X512 <danger_mail@xxxxxxx>:
Hello Please take over this change,
I'd like you to do a code review. Please visit
https://review.haiku-os.org/c/haiku/+/2874
to review the following change.
Change subject: kernel/x86_64: IA32 compatibility mode.
......................................................................
kernel/x86_64: IA32 compatibility mode.
Change-Id: I3fc15613d4443b50980291d8f9300dc550ed95b0
---
M headers/private/kernel/arch/thread.h
M headers/private/kernel/arch/x86/arch_cpu.h
M headers/private/kernel/arch/x86/arch_thread.h
A headers/private/kernel/compat/OS_compat.h
A headers/private/kernel/compat/arch/x86/signal_compat.h
A headers/private/kernel/compat/fcntl_compat.h
A headers/private/kernel/compat/fs_attr_compat.h
A headers/private/kernel/compat/fs_info_compat.h
A headers/private/kernel/compat/image_compat.h
A headers/private/kernel/compat/ksignal_compat.h
A headers/private/kernel/compat/resource_compat.h
A headers/private/kernel/compat/signal_compat.h
A headers/private/kernel/compat/stat_compat.h
A headers/private/kernel/compat/thread_defs_compat.h
A headers/private/kernel/compat/time_compat.h
A headers/private/kernel/compat/vfs_defs_compat.h
M headers/private/kernel/elf_priv.h
M headers/private/kernel/util/syscall_args.h
M headers/private/kernel/vm/VMAddressSpace.h
M headers/private/system/thread_defs.h
M src/system/kernel/Jamfile
M src/system/kernel/UserTimer.cpp
M src/system/kernel/arch/x86/64/arch.S
M src/system/kernel/arch/x86/64/thread.cpp
M src/system/kernel/arch/x86/Jamfile
M src/system/kernel/arch/x86/arch_debug.cpp
M src/system/kernel/arch/x86/arch_thread.cpp
M src/system/kernel/debug/Jamfile
M src/system/kernel/debug/safemode_settings.cpp
M src/system/kernel/disk_device_manager/Jamfile
M src/system/kernel/disk_device_manager/ddm_userland_interface.cpp
M src/system/kernel/fs/Jamfile
M src/system/kernel/fs/socket.cpp
M src/system/kernel/fs/vfs.cpp
M src/system/kernel/image.cpp
M src/system/kernel/signal.cpp
M src/system/kernel/system_info.cpp
M src/system/kernel/team.cpp
M src/system/kernel/thread.cpp
M src/system/kernel/vm/Jamfile
M src/system/kernel/vm/VMUserAddressSpace.cpp
M src/system/kernel/vm/VMUserAddressSpace.h
M src/system/kernel/vm/vm.cpp
43 files changed, 2,534 insertions(+), 237 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/74/2874/1
diff --git a/headers/private/kernel/arch/thread.h
b/headers/private/kernel/arch/thread.h
index b19066a..5556073 100644
--- a/headers/private/kernel/arch/thread.h
+++ b/headers/private/kernel/arch/thread.h
@@ -31,6 +31,12 @@
status_t arch_setup_signal_frame(Thread *thread, struct sigaction *action,
struct signal_frame_data *signalFrameData);
int64 arch_restore_signal_frame(struct signal_frame_data* signalFrameData);
+#ifdef _COMPAT_MODE
+status_t arch_setup_compat_signal_frame(Thread *thread,
+ struct sigaction *action, struct compat_signal_frame_data
*signalFrameData);
+int64 arch_restore_compat_signal_frame(
+ struct compat_signal_frame_data* signalFrameData);
+#endif
void arch_store_fork_frame(struct arch_fork_arg *arg);
void arch_restore_fork_frame(struct arch_fork_arg *arg);
diff --git a/headers/private/kernel/arch/x86/arch_cpu.h
b/headers/private/kernel/arch/x86/arch_cpu.h
index fa5215e..921b322 100644
--- a/headers/private/kernel/arch/x86/arch_cpu.h
+++ b/headers/private/kernel/arch/x86/arch_cpu.h
@@ -640,9 +640,6 @@
void x86_context_switch(struct arch_thread* oldState,
struct arch_thread* newState);
-void x86_fnsave(void* fpuState);
-void x86_frstor(const void* fpuState);
-
void x86_fxsave(void* fpuState);
void x86_fxrstor(const void* fpuState);
@@ -653,6 +650,14 @@
#endif
+#if !defined(__x86_64__) || defined(_COMPAT_MODE)
+
+void x86_fnsave(void* fpuState);
+void x86_frstor(const void* fpuState);
+
+#endif // !defined(__x86_64__) || defined(_COMPAT_MODE)
+
+
static inline void
arch_cpu_idle(void)
{
diff --git a/headers/private/kernel/arch/x86/arch_thread.h
b/headers/private/kernel/arch/x86/arch_thread.h
index 3689d0b..2415110 100644
--- a/headers/private/kernel/arch/x86/arch_thread.h
+++ b/headers/private/kernel/arch/x86/arch_thread.h
@@ -51,6 +51,30 @@
}
+#ifdef _COMPAT_MODE
+
+
+static inline void
+arch_thread_set_ds(unsigned short ds)
+{
+ asm volatile("mov %0, %%ds" : : "r" (ds) : "memory");
+}
+
+
+static inline void
+arch_thread_set_es(unsigned short es)
+{
+ asm volatile("mov %0, %%es" : : "r" (es) : "memory");
+}
+
+// override empty macro
+#undef arch_syscall_64_bit_return_value
+void arch_syscall_64_bit_return_value(void);
+
+
+#endif // _COMPAT_MODE
+
+
#else // __x86_64__
diff --git a/headers/private/kernel/compat/OS_compat.h
b/headers/private/kernel/compat/OS_compat.h
new file mode 100644
index 0000000..4978d50
--- /dev/null
+++ b/headers/private/kernel/compat/OS_compat.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_OS_H
+#define _KERNEL_COMPAT_OS_H
+
+
+#include <thread.h>
+
+
+typedef struct {
+ bigtime_t boot_time; /* time of boot
(usecs since 1/1/1970) */
+
+ uint32 cpu_count; /* number of
cpus */
+
+ uint64 max_pages; /* total # of
accessible pages */
+ uint64 used_pages; /* # of
accessible pages in use */
+ uint64 cached_pages;
+ uint64 block_cache_pages;
+ uint64 ignored_pages; /* # of
ignored/inaccessible pages */
+
+ uint64 needed_memory;
+ uint64 free_memory;
+
+ uint64 max_swap_pages;
+ uint64 free_swap_pages;
+
+ uint32 page_faults; /* # of page faults */
+
+ uint32 max_sems;
+ uint32 used_sems;
+
+ uint32 max_ports;
+ uint32 used_ports;
+
+ uint32 max_threads;
+ uint32 used_threads;
+
+ uint32 max_teams;
+ uint32 used_teams;
+
+ char kernel_name[B_FILE_NAME_LENGTH];
+ char kernel_build_date[B_OS_NAME_LENGTH];
+ char kernel_build_time[B_OS_NAME_LENGTH];
+
+ int64 kernel_version;
+ uint32 abi; /* the system
API */
+} _PACKED compat_system_info;
+
+
+static_assert(sizeof(compat_system_info) == 0x1c4,
+ "size of compat_system_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(system_info &info, system_info* userInfo)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_system_info compat_info;
+ compat_info.boot_time = info.boot_time;
+ compat_info.cpu_count = info.cpu_count;
+ compat_info.max_pages = info.max_pages;
+ compat_info.used_pages = info.used_pages;
+ compat_info.cached_pages = info.cached_pages;
+ compat_info.block_cache_pages = info.block_cache_pages;
+ compat_info.ignored_pages = info.ignored_pages;
+ compat_info.needed_memory = info.needed_memory;
+ compat_info.free_memory = info.free_memory;
+ compat_info.needed_memory = info.needed_memory;
+ compat_info.max_swap_pages = info.max_swap_pages;
+ compat_info.free_swap_pages = info.free_swap_pages;
+ compat_info.max_sems = info.max_sems;
+ compat_info.used_sems = info.used_sems;
+ compat_info.max_ports = info.max_ports;
+ compat_info.used_ports = info.used_ports;
+ compat_info.max_threads = info.max_threads;
+ compat_info.used_threads = info.used_threads;
+ compat_info.max_teams = info.max_teams;
+ compat_info.used_teams = info.used_teams;
+ strlcpy(compat_info.kernel_name, info.kernel_name,
B_FILE_NAME_LENGTH);
+ strlcpy(compat_info.kernel_build_date, info.kernel_build_date,
+ B_OS_NAME_LENGTH);
+ strlcpy(compat_info.kernel_build_time, info.kernel_build_time,
+ B_OS_NAME_LENGTH);
+ compat_info.kernel_version = info.kernel_version;
+ compat_info.abi = info.abi;
+ if (user_memcpy(userInfo, &compat_info, sizeof(compat_info)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else if (user_memcpy(userInfo, &info, sizeof(system_info)) < B_OK)
+ return B_BAD_ADDRESS;
+ return B_OK;
+}
+
+
+#define compat_size_t uint32
+#define compat_ptr_t uint32
+typedef struct compat_area_info {
+ area_id area;
+ char name[B_OS_NAME_LENGTH];
+ compat_size_t size;
+ uint32 lock;
+ uint32 protection;
+ team_id team;
+ uint32 ram_size;
+ uint32 copy_count;
+ uint32 in_count;
+ uint32 out_count;
+ compat_ptr_t address;
+} _PACKED compat_area_info;
+
+
+static_assert(sizeof(compat_area_info) == 0x48,
+ "size of compat_area_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(area_info &info, area_info* userInfo)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_area_info compatInfo;
+ compatInfo.area = info.area;
+ strlcpy(compatInfo.name, info.name, B_OS_NAME_LENGTH);
+ compatInfo.size = info.size;
+ compatInfo.lock = info.lock;
+ compatInfo.protection = info.protection;
+ compatInfo.team = info.team;
+ compatInfo.ram_size = info.ram_size;
+ compatInfo.copy_count = info.copy_count;
+ compatInfo.in_count = info.in_count;
+ compatInfo.out_count = info.out_count;
+ compatInfo.address = (compat_ptr_t)(addr_t)info.address;
+ if (user_memcpy(userInfo, &compatInfo, sizeof(compatInfo)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+typedef struct {
+ thread_id thread;
+ team_id team;
+ char name[B_OS_NAME_LENGTH];
+ thread_state state;
+ int32 priority;
+ sem_id sem;
+ bigtime_t user_time;
+ bigtime_t kernel_time;
+ uint32 stack_base;
+ uint32 stack_end;
+} _PACKED compat_thread_info;
+
+
+static_assert(sizeof(compat_thread_info) == 76,
+ "size of compat_thread_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(thread_info &info, thread_info* userInfo)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_thread_info compatInfo;
+ compatInfo.thread = info.thread;
+ compatInfo.team = info.team;
+ strlcpy(compatInfo.name, info.name, sizeof(compatInfo.name));
+ compatInfo.state = info.state;
+ compatInfo.priority = info.priority;
+ compatInfo.sem = info.sem;
+ compatInfo.user_time = info.user_time;
+ compatInfo.kernel_time = info.kernel_time;
+ compatInfo.stack_base = (uint32)(addr_t)info.stack_base;
+ compatInfo.stack_end = (uint32)(addr_t)info.stack_end;
+ if (user_memcpy(userInfo, &compatInfo, sizeof(compatInfo)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(void* &addr, void** userAddr)
+{
+ if (!IS_USER_ADDRESS(userAddr))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_ptr_t compatAddr = (uint32)(addr_t)addr;
+ if (user_memcpy(userAddr, &compatAddr, sizeof(compatAddr)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else if (user_memcpy(userAddr, &addr, sizeof(addr)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(void** userAddr, void* &addr)
+{
+ if (!IS_USER_ADDRESS(userAddr))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_ptr_t compatAddr;
+ if (user_memcpy(&compatAddr, userAddr, sizeof(compatAddr)) <
B_OK)
+ return B_BAD_ADDRESS;
+ addr = (void*)(addr_t)compatAddr;
+ } else if (user_memcpy(&addr, userAddr, sizeof(addr)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(addr_t &addr, addr_t* userAddr)
+{
+ if (!IS_USER_ADDRESS(userAddr))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ uint32 compatAddr = (uint32)addr;
+ if (user_memcpy(userAddr, &compatAddr, sizeof(compatAddr)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else if (user_memcpy(userAddr, &addr, sizeof(addr)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(addr_t* userAddr, addr_t &addr)
+{
+ if (!IS_USER_ADDRESS(userAddr))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ uint32 compatAddr;
+ if (user_memcpy(&compatAddr, userAddr, sizeof(compatAddr)) <
B_OK)
+ return B_BAD_ADDRESS;
+ addr = (addr_t)compatAddr;
+ } else if (user_memcpy(&addr, userAddr, sizeof(addr)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(ssize_t &size, ssize_t* userSize)
+{
+ if (!IS_USER_ADDRESS(userSize))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ int32 compatSize = (int32)size;
+ if (user_memcpy(userSize, &compatSize, sizeof(compatSize)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else if (user_memcpy(userSize, &size, sizeof(size)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(ssize_t* userSize, ssize_t &size)
+{
+ if (!IS_USER_ADDRESS(userSize))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ int32 compatSize;
+ if (user_memcpy(&compatSize, userSize, sizeof(compatSize)) <
B_OK)
+ return B_BAD_ADDRESS;
+ size = (ssize_t)compatSize;
+ } else if (user_memcpy(&size, userSize, sizeof(size)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_OS_H
diff --git a/headers/private/kernel/compat/arch/x86/signal_compat.h
b/headers/private/kernel/compat/arch/x86/signal_compat.h
new file mode 100644
index 0000000..8fe645d
--- /dev/null
+++ b/headers/private/kernel/compat/arch/x86/signal_compat.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_ARCH_SIGNAL_H
+#define _KERNEL_COMPAT_ARCH_SIGNAL_H
+
+
+typedef struct packed_fp_stack {
+ unsigned char st0[10];
+ unsigned char st1[10];
+ unsigned char st2[10];
+ unsigned char st3[10];
+ unsigned char st4[10];
+ unsigned char st5[10];
+ unsigned char st6[10];
+ unsigned char st7[10];
+} packed_fp_stack;
+
+typedef struct packed_mmx_regs {
+ unsigned char mm0[10];
+ unsigned char mm1[10];
+ unsigned char mm2[10];
+ unsigned char mm3[10];
+ unsigned char mm4[10];
+ unsigned char mm5[10];
+ unsigned char mm6[10];
+ unsigned char mm7[10];
+} packed_mmx_regs;
+
+typedef struct xmmx_regs {
+ unsigned char xmm0[16];
+ unsigned char xmm1[16];
+ unsigned char xmm2[16];
+ unsigned char xmm3[16];
+ unsigned char xmm4[16];
+ unsigned char xmm5[16];
+ unsigned char xmm6[16];
+ unsigned char xmm7[16];
+} xmmx_regs;
+
+typedef struct compat_stack_t {
+ uint32 ss_sp;
+ uint32 ss_size;
+ int ss_flags;
+} compat_stack_t;
+
+typedef struct compat_old_extended_regs {
+ unsigned short fp_control;
+ unsigned short _reserved1;
+ unsigned short fp_status;
+ unsigned short _reserved2;
+ unsigned short fp_tag;
+ unsigned short _reserved3;
+ uint32 fp_eip;
+ unsigned short fp_cs;
+ unsigned short fp_opcode;
+ uint32 fp_datap;
+ unsigned short fp_ds;
+ unsigned short _reserved4;
+ union {
+ packed_fp_stack fp;
+ packed_mmx_regs mmx;
+ } fp_mmx;
+} compat_old_extended_regs;
+
+typedef struct compat_new_extended_regs {
+ unsigned short fp_control;
+ unsigned short fp_status;
+ unsigned short fp_tag;
+ unsigned short fp_opcode;
+ uint32 fp_eip;
+ unsigned short fp_cs;
+ unsigned short res_14_15;
+ uint32 fp_datap;
+ unsigned short fp_ds;
+ unsigned short _reserved_22_23;
+ uint32 mxcsr;
+ uint32 _reserved_28_31;
+ union {
+ fp_stack fp;
+ mmx_regs mmx;
+ } fp_mmx;
+ xmmx_regs xmmx;
+ unsigned char _reserved_288_511[224];
+} compat_new_extended_regs;
+
+typedef struct compat_extended_regs {
+ union {
+ compat_old_extended_regs old_format;
+ compat_new_extended_regs new_format;
+ } state;
+ uint32 format;
+} compat_extended_regs;
+
+struct compat_vregs {
+ uint32 eip;
+ uint32 eflags;
+ uint32 eax;
+ uint32 ecx;
+ uint32 edx;
+ uint32 esp;
+ uint32 ebp;
+ uint32 _reserved_1;
+ compat_extended_regs xregs;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebx;
+};
+
+
+#endif // _KERNEL_COMPAT_ARCH_SIGNAL_H
diff --git a/headers/private/kernel/compat/fcntl_compat.h
b/headers/private/kernel/compat/fcntl_compat.h
new file mode 100644
index 0000000..25b38e7
--- /dev/null
+++ b/headers/private/kernel/compat/fcntl_compat.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_FCNTL_H
+#define _KERNEL_COMPAT_FCNTL_H
+
+
+#include <fcntl.h>
+
+
+struct compat_flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+} _PACKED;
+
+
+static_assert(sizeof(struct compat_flock) == 24,
+ "size of compat_flock mismatch");
+
+
+inline status_t
+copy_ref_var_from_user(struct flock* userFlock, struct flock &flock)
+{
+ if (!IS_USER_ADDRESS(userFlock))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_flock compat_flock;
+ if (user_memcpy(&compat_flock, userFlock, sizeof(compat_flock))
< B_OK)
+ return B_BAD_ADDRESS;
+ flock.l_type = compat_flock.l_type;
+ flock.l_whence = compat_flock.l_whence;
+ flock.l_start = compat_flock.l_start;
+ flock.l_len = compat_flock.l_len;
+ flock.l_pid = compat_flock.l_pid;
+ } else {
+ if (user_memcpy(&flock, userFlock, sizeof(struct flock)) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(struct flock &flock, struct flock* userFlock)
+{
+ if (!IS_USER_ADDRESS(userFlock))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_flock compat_flock;
+ compat_flock.l_type = flock.l_type;
+ compat_flock.l_whence = flock.l_whence;
+ compat_flock.l_start = flock.l_start;
+ compat_flock.l_len = flock.l_len;
+ compat_flock.l_pid = flock.l_pid;
+ if (user_memcpy(userFlock, &compat_flock, sizeof(compat_flock))
< B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (user_memcpy(userFlock, &flock, sizeof(flock)) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_FCNTL_H
diff --git a/headers/private/kernel/compat/fs_attr_compat.h
b/headers/private/kernel/compat/fs_attr_compat.h
new file mode 100644
index 0000000..b657fb9
--- /dev/null
+++ b/headers/private/kernel/compat/fs_attr_compat.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_FS_ATTR_H
+#define _KERNEL_COMPAT_FS_ATTR_H
+
+
+#include <fs_attr.h>
+
+
+struct compat_attr_info {
+ uint32 type;
+ off_t size;
+} _PACKED;
+
+
+static_assert(sizeof(compat_attr_info) == 12,
+ "size of compat_attr_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(attr_info &info, attr_info* userInfo)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_attr_info compat_info;
+ compat_info.type = info.type;
+ compat_info.size = info.size;
+ if (user_memcpy(userInfo, &compat_info, sizeof(compat_info)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_FS_ATTR_H
diff --git a/headers/private/kernel/compat/fs_info_compat.h
b/headers/private/kernel/compat/fs_info_compat.h
new file mode 100644
index 0000000..67934bc
--- /dev/null
+++ b/headers/private/kernel/compat/fs_info_compat.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_FS_INFO_H
+#define _KERNEL_COMPAT_FS_INFO_H
+
+
+#include <fs_info.h>
+
+
+typedef struct compat_fs_info {
+ dev_t dev;
/* volume dev_t */
+ ino_t root;
/* root ino_t */
+ uint32 flags;
/* flags (see above) */
+ off_t block_size;
/* fundamental block size */
+ off_t io_size;
/* optimal i/o size */
+ off_t total_blocks; /*
total number of blocks */
+ off_t free_blocks; /*
number of free blocks */
+ off_t total_nodes; /*
total number of nodes */
+ off_t free_nodes;
/* number of free nodes */
+ char device_name[128]; /*
device holding fs */
+ char volume_name[B_FILE_NAME_LENGTH]; /* volume name */
+ char fsh_name[B_OS_NAME_LENGTH]; /* name of fs
handler */
+} _PACKED compat_fs_info;
+
+
+static_assert(sizeof(compat_fs_info) == 480,
+ "size of compat_fs_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(fs_info &info, fs_info* userInfo)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_fs_info compat_info;
+ compat_info.dev = info.dev;
+ compat_info.root = info.root;
+ compat_info.flags = info.flags;
+ compat_info.block_size = info.block_size;
+ compat_info.io_size = info.io_size;
+ compat_info.total_blocks = info.total_blocks;
+ compat_info.free_blocks = info.free_blocks;
+ compat_info.total_nodes = info.total_nodes;
+ compat_info.free_nodes = info.free_nodes;
+ strlcpy(compat_info.device_name, info.device_name, 128);
+ strlcpy(compat_info.volume_name, info.volume_name,
B_FILE_NAME_LENGTH);
+ strlcpy(compat_info.fsh_name, info.fsh_name, B_OS_NAME_LENGTH);
+ if (user_memcpy(userInfo, &compat_info, sizeof(compat_info)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(fs_info* userInfo, fs_info &info)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_fs_info compat_info;
+ if (user_memcpy(&compat_info, userInfo, sizeof(compat_info)) <
B_OK)
+ return B_BAD_ADDRESS;
+ info.dev = compat_info.dev;
+ info.root = compat_info.root;
+ info.flags = compat_info.flags;
+ info.block_size = compat_info.block_size;
+ info.io_size = compat_info.io_size;
+ info.total_blocks = compat_info.total_blocks;
+ info.free_blocks = compat_info.free_blocks;
+ info.total_nodes = compat_info.total_nodes;
+ info.free_nodes = compat_info.free_nodes;
+ strlcpy(info.device_name, compat_info.device_name, 128);
+ strlcpy(info.volume_name, compat_info.volume_name,
B_FILE_NAME_LENGTH);
+ strlcpy(info.fsh_name, compat_info.fsh_name, B_OS_NAME_LENGTH);
+ } else if (user_memcpy(&info, userInfo, sizeof(info)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_FS_INFO_H
diff --git a/headers/private/kernel/compat/image_compat.h
b/headers/private/kernel/compat/image_compat.h
new file mode 100644
index 0000000..eb52f03
--- /dev/null
+++ b/headers/private/kernel/compat/image_compat.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_IMAGE_H
+#define _KERNEL_COMPAT_IMAGE_H
+
+
+#include <image.h>
+
+
+#define compat_uintptr_t uint32
+typedef struct {
+ image_id id;
+ image_type type;
+ int32 sequence;
+ int32 init_order;
+ compat_uintptr_t init_routine;
+ compat_uintptr_t term_routine;
+ dev_t device;
+ ino_t node;
+ char name[MAXPATHLEN];
+ compat_uintptr_t text;
+ compat_uintptr_t data;
+ int32 text_size;
+ int32 data_size;
+
+ /* Haiku R1 extensions */
+ int32 api_version; /* the Haiku API version used by the
image */
+ int32 abi; /* the Haiku ABI used by the
image */
+} _PACKED compat_image_info;
+
+
+typedef struct {
+ compat_image_info basic_info;
+ int32 text_delta;
+ compat_uintptr_t symbol_table;
+ compat_uintptr_t symbol_hash;
+ compat_uintptr_t string_table;
+} _PACKED compat_extended_image_info;
+
+
+static_assert(sizeof(compat_image_info) == 1084,
+ "size of compat_image_info mismatch");
+static_assert(sizeof(compat_extended_image_info) == 1100,
+ "size of compat_extended_image_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(image_info &info, image_info* userInfo, size_t size)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ if (size > sizeof(compat_image_info))
+ return B_BAD_VALUE;
+ compat_image_info compat_info;
+ compat_info.id = info.id;
+ compat_info.type = info.type;
+ compat_info.sequence = info.sequence;
+ compat_info.init_order = info.init_order;
+ compat_info.init_routine = (uint32)(addr_t)info.init_routine;
+ compat_info.term_routine = (uint32)(addr_t)info.term_routine;
+ compat_info.device = info.device;
+ compat_info.node = info.node;
+ strlcpy(compat_info.name, info.name, MAXPATHLEN);
+ compat_info.text = (uint32)(addr_t)info.text;
+ compat_info.data = (uint32)(addr_t)info.data;
+ compat_info.text_size = info.text_size;
+ compat_info.data_size = info.data_size;
+ if (user_memcpy(userInfo, &compat_info, size) < B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (size > sizeof(image_info))
+ return B_BAD_VALUE;
+
+ if (user_memcpy(userInfo, &info, size) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(extended_image_info* userInfo,
+ extended_image_info &info, size_t size)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_extended_image_info compat_info;
+ if (size != sizeof(compat_info))
+ return B_BAD_VALUE;
+ if (user_memcpy(&compat_info, userInfo, size) < B_OK)
+ return B_BAD_ADDRESS;
+ info.basic_info.id = compat_info.basic_info.id;
+ info.basic_info.type = compat_info.basic_info.type;
+ info.basic_info.sequence = compat_info.basic_info.sequence;
+ info.basic_info.init_order = compat_info.basic_info.init_order;
+ info.basic_info.init_routine =
(void(*)())(addr_t)compat_info.basic_info.init_routine;
+ info.basic_info.term_routine =
(void(*)())(addr_t)compat_info.basic_info.term_routine;
+ info.basic_info.device = compat_info.basic_info.device;
+ info.basic_info.node = compat_info.basic_info.node;
+ strlcpy(info.basic_info.name, compat_info.basic_info.name,
MAXPATHLEN);
+ info.basic_info.text =
(void*)(addr_t)compat_info.basic_info.text;
+ info.basic_info.data =
(void*)(addr_t)compat_info.basic_info.data;
+ info.basic_info.text_size = compat_info.basic_info.text_size;
+ info.basic_info.data_size = compat_info.basic_info.data_size;
+ info.text_delta = compat_info.text_delta;
+ info.symbol_table = (void*)(addr_t)compat_info.symbol_table;
+ info.symbol_hash = (void*)(addr_t)compat_info.symbol_hash;
+ info.string_table = (void*)(addr_t)compat_info.string_table;
+ } else {
+ if (size != sizeof(info))
+ return B_BAD_VALUE;
+
+ if (user_memcpy(&info, userInfo, size) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_IMAGE_H
diff --git a/headers/private/kernel/compat/ksignal_compat.h
b/headers/private/kernel/compat/ksignal_compat.h
new file mode 100644
index 0000000..cf25c88
--- /dev/null
+++ b/headers/private/kernel/compat/ksignal_compat.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_KSIGNAL_H
+#define _KERNEL_COMPAT_KSIGNAL_H
+
+
+#include <compat/signal_compat.h>
+#include <compat/arch/x86/signal_compat.h>
+
+
+typedef struct compat_vregs compat_mcontext_t;
+
+typedef struct __compat_ucontext_t {
+ uint32 uc_link;
+ sigset_t uc_sigmask;
+ compat_stack_t uc_stack;
+ compat_mcontext_t uc_mcontext;
+} _PACKED compat_ucontext_t;
+
+
+struct compat_signal_frame_data {
+ compat_siginfo_t info;
+ compat_ucontext_t context;
+ uint32 user_data;
+ uint32 handler;
+ bool siginfo_handler;
+ char _pad[3];
+ int32 thread_flags;
+ uint64 syscall_restart_return_value;
+ uint8
syscall_restart_parameters[SYSCALL_RESTART_PARAMETER_SIZE];
+ uint32 commpage_address;
+} _PACKED;
+
+
+static_assert(sizeof(compat_stack_t) == 12,
+ "size of compat_stack_t mismatch");
+static_assert(sizeof(compat_mcontext_t) == 560,
+ "size of compat_mcontext_t mismatch");
+static_assert(sizeof(compat_ucontext_t) == 584,
+ "size of compat_ucontext_t mismatch");
+static_assert(sizeof(struct compat_signal_frame_data) == 680,
+ "size of compat_signal_frame_data mismatch");
+
+
+inline status_t
+copy_ref_var_from_user(stack_t* userStack, stack_t &stack)
+{
+ if (!IS_USER_ADDRESS(userStack))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_stack_t compatStack;
+ if (user_memcpy(&compatStack, userStack, sizeof(compatStack))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ stack.ss_sp = (void*)(addr_t)compatStack.ss_sp;
+ stack.ss_size = compatStack.ss_size;
+ stack.ss_flags = compatStack.ss_flags;
+ } else if (user_memcpy(&stack, userStack, sizeof(stack_t)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(stack_t &stack, stack_t* userStack)
+{
+ if (!IS_USER_ADDRESS(userStack))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_stack_t compatStack;
+ compatStack.ss_sp = (addr_t)stack.ss_sp;
+ compatStack.ss_size = stack.ss_size;
+ compatStack.ss_flags = stack.ss_flags;
+ if (user_memcpy(userStack, &compatStack, sizeof(compatStack))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ } else if (user_memcpy(userStack, &stack, sizeof(stack)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_KSIGNAL_H
diff --git a/headers/private/kernel/compat/resource_compat.h
b/headers/private/kernel/compat/resource_compat.h
new file mode 100644
index 0000000..4a3c5db
--- /dev/null
+++ b/headers/private/kernel/compat/resource_compat.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_RESOURCE_H
+#define _KERNEL_COMPAT_RESOURCE_H
+
+
+#include <sys/resource.h>
+
+
+typedef uint32 compat_rlim_t;
+struct compat_rlimit {
+ compat_rlim_t rlim_cur; /* current soft limit */
+ compat_rlim_t rlim_max; /* hard limit */
+};
+
+
+inline status_t
+copy_ref_var_to_user(struct rlimit &rl, struct rlimit* urlp)
+{
+ if (!IS_USER_ADDRESS(urlp))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_rlimit compat_rl;
+ compat_rl.rlim_cur = rl.rlim_cur;
+ compat_rl.rlim_max = rl.rlim_max;
+ if (user_memcpy(urlp, &compat_rl, sizeof(compat_rl)) < B_OK)
+ return B_BAD_ADDRESS;
+ } else if (user_memcpy(urlp, &rl, sizeof(rl)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(struct rlimit* urlp, struct rlimit &rl)
+{
+ if (!IS_USER_ADDRESS(urlp))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_rlimit compat_rl;
+ if (user_memcpy(&compat_rl, urlp, sizeof(compat_rl)) < B_OK)
+ return B_BAD_ADDRESS;
+ rl.rlim_cur = compat_rl.rlim_cur;
+ rl.rlim_max = compat_rl.rlim_max;
+ } else if (user_memcpy(&rl, urlp, sizeof(rl)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_RESOURCE_H
diff --git a/headers/private/kernel/compat/signal_compat.h
b/headers/private/kernel/compat/signal_compat.h
new file mode 100644
index 0000000..e8fcac2
--- /dev/null
+++ b/headers/private/kernel/compat/signal_compat.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_SIGNAL_H
+#define _KERNEL_COMPAT_SIGNAL_H
+
+
+#include <thread.h>
+
+
+union compat_sigval {
+ int sival_int;
+ uint32 sival_ptr;
+};
+
+
+inline status_t
+copy_ref_var_from_user(union sigval* userSigval, union sigval &sigval)
+{
+ if (!IS_USER_ADDRESS(userSigval))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_sigval compat_sigval;
+ if (user_memcpy(&compat_sigval, userSigval,
sizeof(compat_sigval))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ sigval.sival_ptr = (void*)(addr_t)compat_sigval.sival_ptr;
+ } else if (user_memcpy(&sigval, userSigval, sizeof(union sigval)) <
B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+struct compat_sigaction {
+ union {
+ uint32 sa_handler;
+ uint32 sa_sigaction;
+ };
+ sigset_t sa_mask;
+ int sa_flags;
+ uint32 sa_userdata; /* will be
passed to the signal
+
handler, BeOS extension */
+} _PACKED;
+
+
+inline status_t
+copy_ref_var_from_user(struct sigaction* userAction, struct sigaction &action)
+{
+ if (!IS_USER_ADDRESS(userAction))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_sigaction compat_action;
+ if (user_memcpy(&compat_action, userAction,
sizeof(compat_sigaction))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ action.sa_handler =
(__sighandler_t)(addr_t)compat_action.sa_handler;
+ action.sa_mask = compat_action.sa_mask;
+ action.sa_flags = compat_action.sa_flags;
+ action.sa_userdata = (void*)(addr_t)compat_action.sa_userdata;
+ } else if (user_memcpy(&action, userAction, sizeof(action)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(struct sigaction &action, struct sigaction* userAction)
+{
+ if (!IS_USER_ADDRESS(userAction))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_sigaction compat_action;
+ compat_action.sa_handler = (addr_t)action.sa_handler;
+ compat_action.sa_mask = action.sa_mask;
+ compat_action.sa_flags = action.sa_flags;
+ compat_action.sa_userdata = (addr_t)action.sa_userdata;
+ if (user_memcpy(userAction, &compat_action,
sizeof(compat_action))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ } else if (user_memcpy(userAction, &action, sizeof(action)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+struct compat_sigevent {
+ int sigev_notify; /* notification type */
+ int sigev_signo; /* signal number */
+ union compat_sigval sigev_value; /* user-defined signal value */
+ uint32 sigev_notify_function;
+ /*
notification function in case of
+
SIGEV_THREAD */
+ uint32 sigev_notify_attributes;
+ /*
pthread creation attributes in case of
+
SIGEV_THREAD */
+} _PACKED;
+
+
+static_assert(sizeof(compat_sigevent) == 20,
+ "size of compat_sigevent mismatch");
+
+
+inline status_t
+copy_ref_var_from_user(struct sigevent* userEvent, struct sigevent &event)
+{
+ if (!IS_USER_ADDRESS(userEvent))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_sigevent compat_event;
+ if (user_memcpy(&compat_event, userEvent,
sizeof(compat_sigevent))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ event.sigev_notify = compat_event.sigev_notify;
+ event.sigev_signo = compat_event.sigev_signo;
+ event.sigev_value.sival_ptr =
+ (void*)(addr_t)compat_event.sigev_value.sival_ptr;
+ event.sigev_notify_function =
+
(void(*)(sigval))(addr_t)compat_event.sigev_notify_function;
+ event.sigev_notify_attributes =
+
(pthread_attr_t*)(addr_t)compat_event.sigev_notify_attributes;
+ } else if (user_memcpy(&event, userEvent, sizeof(event)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+typedef struct __compat_siginfo_t {
+ int si_signo; /* signal number */
+ int si_code; /* signal code */
+ int si_errno; /* if non zero, an
error number associated with
+ this signal
*/
+ pid_t si_pid; /* sending process ID */
+ uid_t si_uid; /* real user ID of sending
process */
+ uint32 si_addr; /* address of faulting
instruction */
+ int si_status; /* exit value or signal
*/
+ uint32 si_band; /* band event for SIGPOLL */
+ union compat_sigval si_value; /* signal value */
+} compat_siginfo_t;
+
+
+static_assert(sizeof(compat_siginfo_t) == 36,
+ "size of compat_siginfo_t mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(siginfo_t &info, siginfo_t* userInfo)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_siginfo_t compat_info;
+ compat_info.si_signo = info.si_signo;
+ compat_info.si_code = info.si_code;
+ compat_info.si_errno = info.si_errno;
+ compat_info.si_pid = info.si_pid;
+ compat_info.si_uid = info.si_uid;
+ compat_info.si_addr = (addr_t)info.si_addr;
+ compat_info.si_status = info.si_status;
+ compat_info.si_band = info.si_band;
+ compat_info.si_value.sival_ptr =
(addr_t)info.si_value.sival_ptr;
+ if (user_memcpy(userInfo, &compat_info, sizeof(compat_info))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ } else if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_SIGNAL_H
diff --git a/headers/private/kernel/compat/stat_compat.h
b/headers/private/kernel/compat/stat_compat.h
new file mode 100644
index 0000000..2fc947a
--- /dev/null
+++ b/headers/private/kernel/compat/stat_compat.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_STAT_H
+#define _KERNEL_COMPAT_STAT_H
+
+
+#include <sys/stat.h>
+#include <time_compat.h>
+
+
+struct compat_stat {
+ dev_t st_dev; /* device ID that this
file resides on */
+ ino_t st_ino; /* this file's serial
inode ID */
+ mode_t st_mode; /* file mode (rwx for
user, group, etc) */
+ nlink_t st_nlink; /* number of hard links
to this file */
+ uid_t st_uid; /* user ID of the owner
of this file */
+ gid_t st_gid; /* group ID of the
owner of this file */
+ off_t st_size; /* size in bytes of
this file */
+ dev_t st_rdev; /* device type (not
used) */
+ blksize_t st_blksize; /* preferred block size
for I/O */
+ struct compat_timespec st_atim; /* last access time */
+ struct compat_timespec st_mtim; /* last modification
time */
+ struct compat_timespec st_ctim; /* last change time,
not creation time */
+ struct compat_timespec st_crtim; /* creation time */
+ __haiku_uint32 st_type; /* attribute/index type */
+ blkcnt_t st_blocks; /* number of blocks
allocated for object */
+} _PACKED;
+
+
+static_assert(sizeof(struct compat_stat) == 88,
+ "size of struct compat_stat mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(struct stat &stat, struct stat* userStat, size_t size)
+{
+ if (!IS_USER_ADDRESS(userStat))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ if (size > sizeof(compat_stat))
+ return B_BAD_VALUE;
+ struct compat_stat compat_stat;
+ compat_stat.st_dev = stat.st_dev;
+ compat_stat.st_ino = stat.st_ino;
+ compat_stat.st_mode = stat.st_mode;
+ compat_stat.st_nlink = stat.st_nlink;
+ compat_stat.st_uid = stat.st_uid;
+ compat_stat.st_gid = stat.st_gid;
+ compat_stat.st_size = stat.st_size;
+ compat_stat.st_rdev = stat.st_rdev;
+ compat_stat.st_blksize = stat.st_blksize;
+ compat_stat.st_atim.tv_sec = stat.st_atim.tv_sec;
+ compat_stat.st_atim.tv_nsec = stat.st_atim.tv_nsec;
+ compat_stat.st_mtim.tv_sec = stat.st_mtim.tv_sec;
+ compat_stat.st_mtim.tv_nsec = stat.st_mtim.tv_nsec;
+ compat_stat.st_ctim.tv_sec = stat.st_ctim.tv_sec;
+ compat_stat.st_ctim.tv_nsec = stat.st_ctim.tv_nsec;
+ compat_stat.st_crtim.tv_sec = stat.st_crtim.tv_sec;
+ compat_stat.st_crtim.tv_nsec = stat.st_crtim.tv_nsec;
+ compat_stat.st_type = stat.st_type;
+ compat_stat.st_blocks = stat.st_blocks;
+ if (user_memcpy(userStat, &compat_stat, size) < B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (size > sizeof(struct stat))
+ return B_BAD_VALUE;
+
+ if (user_memcpy(userStat, &stat, size) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(struct stat &stat, struct stat* userStat)
+{
+ if (!IS_USER_ADDRESS(userStat))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_stat compat_stat;
+ compat_stat.st_dev = stat.st_dev;
+ compat_stat.st_ino = stat.st_ino;
+ compat_stat.st_mode = stat.st_mode;
+ compat_stat.st_nlink = stat.st_nlink;
+ compat_stat.st_uid = stat.st_uid;
+ compat_stat.st_gid = stat.st_gid;
+ compat_stat.st_size = stat.st_size;
+ compat_stat.st_rdev = stat.st_rdev;
+ compat_stat.st_blksize = stat.st_blksize;
+ compat_stat.st_atim.tv_sec = stat.st_atim.tv_sec;
+ compat_stat.st_atim.tv_nsec = stat.st_atim.tv_nsec;
+ compat_stat.st_mtim.tv_sec = stat.st_mtim.tv_sec;
+ compat_stat.st_mtim.tv_nsec = stat.st_mtim.tv_nsec;
+ compat_stat.st_ctim.tv_sec = stat.st_ctim.tv_sec;
+ compat_stat.st_ctim.tv_nsec = stat.st_ctim.tv_nsec;
+ compat_stat.st_crtim.tv_sec = stat.st_crtim.tv_sec;
+ compat_stat.st_crtim.tv_nsec = stat.st_crtim.tv_nsec;
+ compat_stat.st_type = stat.st_type;
+ compat_stat.st_blocks = stat.st_blocks;
+ if (user_memcpy(userStat, &compat_stat, sizeof(compat_stat)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (user_memcpy(userStat, &stat, sizeof(stat)) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(struct stat* userStat, struct stat &stat, size_t size)
+{
+ if (!IS_USER_ADDRESS(userStat))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_stat compat_stat;
+ if (user_memcpy(&compat_stat, userStat, size) < B_OK)
+ return B_BAD_ADDRESS;
+ stat.st_dev = compat_stat.st_dev;
+ stat.st_ino = compat_stat.st_ino;
+ stat.st_mode = compat_stat.st_mode;
+ stat.st_nlink = compat_stat.st_nlink;
+ stat.st_uid = compat_stat.st_uid;
+ stat.st_gid = compat_stat.st_gid;
+ stat.st_size = compat_stat.st_size;
+ stat.st_rdev = compat_stat.st_rdev;
+ stat.st_blksize = compat_stat.st_blksize;
+ stat.st_atim.tv_sec = compat_stat.st_atim.tv_sec;
+ stat.st_atim.tv_nsec = compat_stat.st_atim.tv_nsec;
+ stat.st_mtim.tv_sec = compat_stat.st_mtim.tv_sec;
+ stat.st_mtim.tv_nsec = compat_stat.st_mtim.tv_nsec;
+ stat.st_ctim.tv_sec = compat_stat.st_ctim.tv_sec;
+ stat.st_ctim.tv_nsec = compat_stat.st_ctim.tv_nsec;
+ stat.st_crtim.tv_sec = compat_stat.st_crtim.tv_sec;
+ stat.st_crtim.tv_nsec = compat_stat.st_crtim.tv_nsec;
+ stat.st_type = compat_stat.st_type;
+ stat.st_blocks = compat_stat.st_blocks;
+ } else if (user_memcpy(&stat, userStat, size) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(struct stat* userStat, struct stat &stat)
+{
+ if (!IS_USER_ADDRESS(userStat))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_stat compat_stat;
+ if (user_memcpy(&compat_stat, userStat, sizeof(compat_stat)) <
B_OK)
+ return B_BAD_ADDRESS;
+ stat.st_dev = compat_stat.st_dev;
+ stat.st_ino = compat_stat.st_ino;
+ stat.st_mode = compat_stat.st_mode;
+ stat.st_nlink = compat_stat.st_nlink;
+ stat.st_uid = compat_stat.st_uid;
+ stat.st_gid = compat_stat.st_gid;
+ stat.st_size = compat_stat.st_size;
+ stat.st_rdev = compat_stat.st_rdev;
+ stat.st_blksize = compat_stat.st_blksize;
+ stat.st_atim.tv_sec = compat_stat.st_atim.tv_sec;
+ stat.st_atim.tv_nsec = compat_stat.st_atim.tv_nsec;
+ stat.st_mtim.tv_sec = compat_stat.st_mtim.tv_sec;
+ stat.st_mtim.tv_nsec = compat_stat.st_mtim.tv_nsec;
+ stat.st_ctim.tv_sec = compat_stat.st_ctim.tv_sec;
+ stat.st_ctim.tv_nsec = compat_stat.st_ctim.tv_nsec;
+ stat.st_crtim.tv_sec = compat_stat.st_crtim.tv_sec;
+ stat.st_crtim.tv_nsec = compat_stat.st_crtim.tv_nsec;
+ stat.st_type = compat_stat.st_type;
+ stat.st_blocks = compat_stat.st_blocks;
+ } else if (user_memcpy(&stat, userStat, sizeof(stat)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+
+
+#endif // _KERNEL_COMPAT_STAT_H
diff --git a/headers/private/kernel/compat/thread_defs_compat.h
b/headers/private/kernel/compat/thread_defs_compat.h
new file mode 100644
index 0000000..340df5a
--- /dev/null
+++ b/headers/private/kernel/compat/thread_defs_compat.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_THREAD_DEFS_H
+#define _KERNEL_COMPAT_THREAD_DEFS_H
+
+
+#include <thread_defs.h>
+
+
+#define compat_ptr_t uint32
+struct compat_thread_creation_attributes {
+ compat_ptr_t entry;
+ compat_ptr_t name;
+ int32 priority;
+ compat_ptr_t args1;
+ compat_ptr_t args2;
+ compat_ptr_t stack_address;
+ uint32_t stack_size;
+ uint32_t guard_size;
+ compat_ptr_t pthread;
+ uint32 flags;
+} _PACKED;
+
+
+static_assert(sizeof(struct compat_thread_creation_attributes) == 40,
+ "size of compat_thread_creation_attributes mismatch");
+
+
+inline status_t
+copy_ref_var_from_user(BKernel::ThreadCreationAttributes* userAttrs,
+ BKernel::ThreadCreationAttributes &attrs)
+{
+ if (!IS_USER_ADDRESS(userAttrs))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_thread_creation_attributes compatAttrs;
+ if (user_memcpy(&compatAttrs, userAttrs, sizeof(compatAttrs)) <
B_OK)
+ return B_BAD_ADDRESS;
+ attrs.entry = (int32 (*)(void*,
void*))(addr_t)compatAttrs.entry;
+ attrs.name = (const char*)(addr_t)compatAttrs.name;
+ attrs.priority = compatAttrs.priority;
+ attrs.args1 = (void*)(addr_t)compatAttrs.args1;
+ attrs.args2 = (void*)(addr_t)compatAttrs.args2;
+ attrs.stack_address = (void*)(addr_t)compatAttrs.stack_address;
+ attrs.stack_size = compatAttrs.stack_size;
+ attrs.guard_size = compatAttrs.guard_size;
+ attrs.pthread = (pthread_t)(addr_t)compatAttrs.pthread;
+ attrs.flags = compatAttrs.flags;
+ } else if (user_memcpy(&attrs, userAttrs, sizeof(attrs)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_THREAD_DEFS_H
diff --git a/headers/private/kernel/compat/time_compat.h
b/headers/private/kernel/compat/time_compat.h
new file mode 100644
index 0000000..819a79d
--- /dev/null
+++ b/headers/private/kernel/compat/time_compat.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_TIME_H
+#define _KERNEL_COMPAT_TIME_H
+
+
+#include <time.h>
+
+
+struct compat_timespec {
+ uint32 tv_sec; /* seconds */
+ uint32 tv_nsec; /* and nanoseconds */
+};
+
+
+#endif // _KERNEL_COMPAT_TIME_H
diff --git a/headers/private/kernel/compat/vfs_defs_compat.h
b/headers/private/kernel/compat/vfs_defs_compat.h
new file mode 100644
index 0000000..7f610d7
--- /dev/null
+++ b/headers/private/kernel/compat/vfs_defs_compat.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_VFS_DEFS_H
+#define _KERNEL_COMPAT_VFS_DEFS_H
+
+
+#include <vfs_defs.h>
+
+
+struct compat_fd_info {
+ int number;
+ int32 open_mode;
+ dev_t device;
+ ino_t node;
+} _PACKED;
+
+
+static_assert(sizeof(compat_fd_info) == 20,
+ "size of compat_fd_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(fd_info &info, fd_info* userInfo, size_t size)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ if (size != sizeof(compat_fd_info))
+ return B_BAD_VALUE;
+ compat_fd_info compat_info;
+ compat_info.number = info.number;
+ compat_info.open_mode = info.open_mode;
+ compat_info.device = info.device;
+ compat_info.node = info.node;
+ if (user_memcpy(userInfo, &compat_info, size) < B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (size != sizeof(fd_info))
+ return B_BAD_VALUE;
+ if (user_memcpy(userInfo, &info, size) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(fd_info &info, fd_info* userInfo)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_fd_info compat_info;
+ compat_info.number = info.number;
+ compat_info.open_mode = info.open_mode;
+ compat_info.device = info.device;
+ compat_info.node = info.node;
+ if (user_memcpy(userInfo, &compat_info, sizeof(compat_info)) <
B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(fd_info* userInfo, fd_info &info, size_t size)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ if (size != sizeof(compat_fd_info))
+ return B_BAD_VALUE;
+ compat_fd_info compat_info;
+ if (user_memcpy(&compat_info, userInfo, size) < B_OK)
+ return B_BAD_ADDRESS;
+ info.number = compat_info.number;
+ info.open_mode = compat_info.open_mode;
+ info.device = compat_info.device;
+ info.node = compat_info.node;
+ } else {
+ if (size != sizeof(fd_info))
+ return B_BAD_VALUE;
+ if (user_memcpy(&info, userInfo, size) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_VFS_DEFS_H
diff --git a/headers/private/kernel/elf_priv.h
b/headers/private/kernel/elf_priv.h
index 50153b8..c91a683 100644
--- a/headers/private/kernel/elf_priv.h
+++ b/headers/private/kernel/elf_priv.h
@@ -82,6 +82,11 @@
extern status_t elf_resolve_symbol(struct elf_image_info* image,
elf_sym* symbol, struct elf_image_info* sharedImage,
elf_addr* _symbolAddress);
+#ifdef _COMPAT_MODE
+extern status_t elf32_resolve_symbol(struct elf_image_info* image,
+ elf_sym* symbol, struct elf_image_info* sharedImage,
+ elf_addr* _symbolAddress);
+#endif
#ifdef __cplusplus
}
diff --git a/headers/private/kernel/util/syscall_args.h
b/headers/private/kernel/util/syscall_args.h
index 5da8294..42358c9 100644
--- a/headers/private/kernel/util/syscall_args.h
+++ b/headers/private/kernel/util/syscall_args.h
@@ -6,27 +6,62 @@
#include <kernel.h>
+#ifndef _COMPAT_MODE
+
// copy_ref_var_from_user
template<typename T>
inline
status_t
copy_ref_var_from_user(T *user, T &kernel)
{
+#ifndef _BOOT_MODE
if (!IS_USER_ADDRESS(user))
return B_BAD_ADDRESS;
+#endif
return user_memcpy(&kernel, user, sizeof(T));
}
+
+template<typename T>
+inline
+status_t
+copy_ref_var_from_user(T *user, T &kernel, size_t size)
+{
+ if (size != sizeof(T))
+ return B_BAD_VALUE;
+ return copy_ref_var_from_user(user, kernel);
+}
+
+
// copy_ref_var_to_user
template<typename T>
inline
status_t
copy_ref_var_to_user(T &kernel, T *user)
{
+#ifndef _BOOT_MODE
if (!IS_USER_ADDRESS(user))
return B_BAD_ADDRESS;
+#endif
return user_memcpy(user, &kernel, sizeof(T));
}
+template<typename T>
+inline
+status_t
+copy_ref_var_to_user(T &kernel, T *user, size_t size)
+{
+ if (size > sizeof(T))
+ return B_BAD_VALUE;
+#ifndef _BOOT_MODE
+ if (!IS_USER_ADDRESS(user))
+ return B_BAD_ADDRESS;
+#endif
+ return user_memcpy(user, &kernel, size);
+}
+
+
+#endif
+
#endif // _SYSCALL_ARGS_H
diff --git a/headers/private/kernel/vm/VMAddressSpace.h
b/headers/private/kernel/vm/VMAddressSpace.h
index 378fb6e..e609be3 100644
--- a/headers/private/kernel/vm/VMAddressSpace.h
+++ b/headers/private/kernel/vm/VMAddressSpace.h
@@ -36,6 +36,10 @@
addr_t Base() const
{ return fBase; }
addr_t EndAddress() const
{ return fEndAddress; }
size_t Size() const { return
fEndAddress - fBase + 1; }
+ virtual void SetSize(size_t size) {
+
fEndAddress = fBase + (size - 1);
+
fFreeSpace = size; }
+
size_t FreeSpace() const
{ return fFreeSpace; }
bool IsBeingDeleted() const
{ return fDeleting; }
diff --git a/headers/private/system/thread_defs.h
b/headers/private/system/thread_defs.h
index e2ba2ee..be1c746 100644
--- a/headers/private/system/thread_defs.h
+++ b/headers/private/system/thread_defs.h
@@ -37,6 +37,10 @@
#define THREAD_CREATION_FLAG_DEFER_SIGNALS 0x01
// create the thread with signals deferred, i.e. with
// user_thread::defer_signals set to 1
+#ifdef _COMPAT_MODE
+# define THREAD_CREATION_FLAG_COMPAT_MODE 0x02
+ // create the thread with a compatibility mode
+#endif
struct thread_creation_attributes {
diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile
index 5f45850..ece7d0e 100644
--- a/src/system/kernel/Jamfile
+++ b/src/system/kernel/Jamfile
@@ -22,6 +22,12 @@
SetVersionScript kernel_$(TARGET_ARCH) : kernel_versions ;
SetVersionScript kernel.so : kernel_versions ;
+local compatSources = ;
+if $(HAIKU_KERNEL_COMPAT_MODE) = 1 {
+ UsePrivateHeaders [ FDirName kernel compat ] ;
+ compatSources = commpage_compat.cpp elf_compat.cpp ;
+}
+
KernelMergeObject kernel_core.o :
boot_item.cpp
boot_splash.cpp
@@ -72,6 +78,8 @@
scheduler_tracing.cpp
scheduling_analysis.cpp
+ # compatibility
+ $(compatSources)
: $(TARGET_KERNEL_PIC_CCFLAGS)
;
diff --git a/src/system/kernel/UserTimer.cpp b/src/system/kernel/UserTimer.cpp
index 2513480..89a0baa 100644
--- a/src/system/kernel/UserTimer.cpp
+++ b/src/system/kernel/UserTimer.cpp
@@ -18,6 +18,12 @@
#include <thread_types.h>
#include <UserEvent.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
+
+#ifdef _COMPAT_MODE
+# include <signal_compat.h>
+# include <user_timer_defs_compat.h>
+#endif
// Minimum interval length in microseconds for a periodic timer. This is not a
@@ -1694,10 +1700,10 @@
// copy the sigevent structure from userland
struct sigevent event = {0};
if (userEvent != NULL) {
- if (!IS_USER_ADDRESS(userEvent)
- || user_memcpy(&event, userEvent, sizeof(event)) !=
B_OK) {
- return B_BAD_ADDRESS;
- }
+ status_t status = copy_ref_var_from_user((struct
sigevent*)userEvent,
+ event);
+ if (status != B_OK)
+ return status;
} else {
// none given -- use defaults
event.sigev_notify = SIGEV_SIGNAL;
@@ -1784,11 +1790,8 @@
timerLocker.Unlock();
// copy it back to userland
- if (userInfo != NULL
- && (!IS_USER_ADDRESS(userInfo)
- || user_memcpy(userInfo, &info, sizeof(info)) != B_OK))
{
- return B_BAD_ADDRESS;
- }
+ if (userInfo != NULL)
+ return copy_ref_var_to_user(info, userInfo);
return B_OK;
}
@@ -1822,11 +1825,8 @@
timerLocker.Unlock();
// copy back the old info
- if (userOldInfo != NULL
- && (!IS_USER_ADDRESS(userOldInfo)
- || user_memcpy(userOldInfo, &oldInfo, sizeof(oldInfo))
!= B_OK)) {
- return B_BAD_ADDRESS;
- }
+ if (userOldInfo != NULL)
+ return copy_ref_var_to_user(oldInfo, userOldInfo);
return B_OK;
}
diff --git a/src/system/kernel/arch/x86/64/arch.S
b/src/system/kernel/arch/x86/64/arch.S
index d88b05b..e0f57f9 100644
--- a/src/system/kernel/arch/x86/64/arch.S
+++ b/src/system/kernel/arch/x86/64/arch.S
@@ -119,3 +119,24 @@
FUNCTION(_clac):
clac
FUNCTION_END(_clac)
+
+
+#ifdef _COMPAT_MODE
+
+
+/* void x86_fnsave(void *fpu_state); */
+FUNCTION(x86_fnsave):
+ movq %rdi, %rax
+ fnsave (%rax)
+ ret
+FUNCTION_END(x86_fnsave)
+
+/* void x86_frstor(const void *fpu_state); */
+FUNCTION(x86_frstor):
+ movq %rdi, %rax
+ frstor (%rax)
+ ret
+FUNCTION_END(x86_frstor)
+
+
+#endif // _COMPAT_MODE
diff --git a/src/system/kernel/arch/x86/64/thread.cpp
b/src/system/kernel/arch/x86/64/thread.cpp
index a29697a..9ae901d 100644
--- a/src/system/kernel/arch/x86/64/thread.cpp
+++ b/src/system/kernel/arch/x86/64/thread.cpp
@@ -27,6 +27,10 @@
#include <vm/vm_types.h>
#include <vm/VMAddressSpace.h>
+#ifdef _COMPAT_MODE
+# include <compat/ksignal_compat.h>
+#endif
+
#include "paging/X86PagingStructures.h"
#include "paging/X86VMTranslationMap.h"
@@ -88,11 +92,33 @@
}
+#ifdef _COMPAT_MODE
+
+
+static inline void
+set_fs_register(uint32 segment)
+{
+ asm("movl %0,%%fs" :: "r" (segment));
+}
+
+
+#endif // _COMPAT_MODE
+
+
void
x86_set_tls_context(Thread* thread)
{
- // Set FS segment base address to the TLS segment.
- x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ unsigned index = x86_64_set_user_tls_segment_base(
+ smp_get_current_cpu(), thread->user_local_storage);
+ set_fs_register((index << 3) | DPL_USER);
+ } else
+#endif
+ {
+ // Set FS segment base address to the TLS segment.
+ x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
+ }
}
@@ -109,6 +135,24 @@
}
+#ifdef _COMPAT_MODE
+
+
+static addr_t
+arch_compat_randomize_stack_pointer(addr_t value)
+{
+ STATIC_ASSERT(MAX_RANDOM_VALUE >= B_PAGE_SIZE - 1);
+ value -= random_value() & (B_PAGE_SIZE - 1);
+ return (value & ~addr_t(0xf)) - 4;
+ // This means, result % 16 == 12, which is what esp should
adhere to
+ // when a function is entered for the stack to be considered
aligned to
+ // 16 byte.
+}
+
+
+#endif // _COMPAT_MODE
+
+
static uint8*
get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action,
size_t spaceNeeded)
@@ -218,27 +262,55 @@
TRACE("arch_thread_enter_userspace: entry %#lx, args %p %p, "
"stackTop %#lx\n", entry, args1, args2, stackTop);
- stackTop = arch_randomize_stack_pointer(stackTop - sizeof(codeAddr));
-
// Copy the address of the stub that calls exit_thread() when the thread
// entry function returns to the top of the stack to act as the return
// address. The stub is inside commpage.
addr_t commPageAddress = (addr_t)thread->team->commpage_address;
- set_ac();
- codeAddr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
- + commPageAddress;
- clear_ac();
- if (user_memcpy((void*)stackTop, (const void*)&codeAddr,
sizeof(codeAddr))
+
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ uint32 args[3];
+ stackTop = arch_compat_randomize_stack_pointer(stackTop -
sizeof(args));
+
+ set_ac();
+ args[0] =
((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
+ + commPageAddress;
+ clear_ac();
+ args[1] = (uint32)(addr_t)args1;
+ args[2] = (uint32)(addr_t)args2;
+ if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
+ return B_BAD_ADDRESS;
+
+ } else
+#endif
+ {
+ stackTop = arch_randomize_stack_pointer(stackTop -
sizeof(codeAddr));
+
+ set_ac();
+ codeAddr =
((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
+ + commPageAddress;
+ clear_ac();
+ if (user_memcpy((void*)stackTop, (const void*)&codeAddr,
sizeof(codeAddr))
!= B_OK)
- return B_BAD_ADDRESS;
+ return B_BAD_ADDRESS;
+ }
// Prepare the user iframe.
iframe frame = {};
frame.type = IFRAME_TYPE_SYSCALL;
- frame.si = (uint64)args2;
- frame.di = (uint64)args1;
frame.ip = entry;
- frame.cs = USER_CODE_SELECTOR;
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ frame.cs = USER32_CODE_SELECTOR;
+ arch_thread_set_ds(USER_DATA_SELECTOR);
+ arch_thread_set_es(USER_DATA_SELECTOR);
+ } else
+#endif
+ {
+ frame.si = (uint64)args2;
+ frame.di = (uint64)args1;
+ frame.cs = USER_CODE_SELECTOR;
+ }
frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
| (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
frame.sp = stackTop;
@@ -394,3 +466,119 @@
// restored.
return frame->ax;
}
+
+
+#ifdef _COMPAT_MODE
+
+status_t
+arch_setup_compat_signal_frame(Thread* thread, struct sigaction* action,
+ struct compat_signal_frame_data* signalFrameData)
+{
+ iframe* frame = x86_get_current_iframe();
+ if (!IFRAME_IS_USER(frame)) {
+ panic("arch_setup_compat_signal_frame(): No user iframe!");
+ return B_BAD_VALUE;
+ }
+
+ // Store the register state.
+ signalFrameData->context.uc_mcontext.eax = frame->ax;
+ signalFrameData->context.uc_mcontext.ebx = frame->bx;
+ signalFrameData->context.uc_mcontext.ecx = frame->cx;
+ signalFrameData->context.uc_mcontext.edx = frame->dx;
+ signalFrameData->context.uc_mcontext.edi = frame->di;
+ signalFrameData->context.uc_mcontext.esi = frame->si;
+ signalFrameData->context.uc_mcontext.ebp = frame->bp;
+ signalFrameData->context.uc_mcontext.esp = frame->user_sp;
+ signalFrameData->context.uc_mcontext.eip = frame->ip;
+ signalFrameData->context.uc_mcontext.eflags = frame->flags;
+ x86_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
+
+ // Fill in signalFrameData->context.uc_stack.
+ stack_t stack;
+ signal_get_user_stack(frame->user_sp, &stack);
+ signalFrameData->context.uc_stack.ss_sp = (addr_t)stack.ss_sp;
+ signalFrameData->context.uc_stack.ss_size = stack.ss_size;
+ signalFrameData->context.uc_stack.ss_flags = stack.ss_flags;
+
+ // Store syscall_restart_return_value.
+ signalFrameData->syscall_restart_return_value = frame->orig_rax;
+
+ // Get the stack to use and copy the frame data to it.
+ uint32 stackFrame[2];
+ uint8* userStack = get_signal_stack(thread, frame, action,
+ sizeof(*signalFrameData) + sizeof(stackFrame));
+
+ compat_signal_frame_data* userSignalFrameData
+ = (compat_signal_frame_data*)(userStack + sizeof(stackFrame));
+
+ if (user_memcpy(userSignalFrameData, signalFrameData,
+ sizeof(*signalFrameData)) != B_OK) {
+ return B_BAD_ADDRESS;
+ }
+
+ // prepare the user stack frame for a function call to the signal
handler
+ // wrapper function
+ stackFrame[0] = frame->ip;
+ stackFrame[1] = (addr_t)userSignalFrameData;
+ // parameter: pointer to signal frame data
+
+ if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
+ return B_BAD_ADDRESS;
+
+ // Update Thread::user_signal_context, now that everything seems to have
+ // gone fine.
+ thread->user_signal_context =
(ucontext_t*)&userSignalFrameData->context;
+
+ // Set up the iframe to execute the signal handler wrapper on our
prepared
+ // stack. First argument points to the frame data.
+ addr_t* commPageAddress = (addr_t*)thread->team->commpage_address;
+ frame->user_sp = (addr_t)userStack;
+ set_ac();
+
+ // from x86/arch_commpage_defs.h
+#define COMPAT_COMMPAGE_ENTRY_X86_SIGNAL_HANDLER \
+ (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 3)
+ frame->ip = commPageAddress[COMPAT_COMMPAGE_ENTRY_X86_SIGNAL_HANDLER]
+ + (addr_t)commPageAddress;
+ clear_ac();
+
+ return B_OK;
+}
+
+
+int64
+arch_restore_compat_signal_frame(struct compat_signal_frame_data*
signalFrameData)
+{
+ iframe* frame = x86_get_current_iframe();
+
+ frame->orig_rax = signalFrameData->syscall_restart_return_value;
+ frame->ax = signalFrameData->context.uc_mcontext.eax;
+ frame->bx = signalFrameData->context.uc_mcontext.ebx;
+ frame->cx = signalFrameData->context.uc_mcontext.ecx;
+ frame->dx = signalFrameData->context.uc_mcontext.edx;
+ frame->di = signalFrameData->context.uc_mcontext.edi;
+ frame->si = signalFrameData->context.uc_mcontext.esi;
+ frame->bp = signalFrameData->context.uc_mcontext.ebp;
+ frame->user_sp = signalFrameData->context.uc_mcontext.esp;
+ frame->ip = signalFrameData->context.uc_mcontext.eip;
+ frame->flags = (frame->flags & ~(uint64)X86_EFLAGS_USER_FLAGS)
+ | (signalFrameData->context.uc_mcontext.eflags &
X86_EFLAGS_USER_FLAGS);
+
+ x86_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
+
+ // The syscall return code overwrites frame->ax with the return value of
+ // the syscall, need to return it here to ensure the correct value is
+ // restored.
+ return frame->ax;
+}
+
+
+void
+arch_syscall_64_bit_return_value(void)
+{
+ Thread* thread = thread_get_current_thread();
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
+ atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN);
+}
+
+#endif // _COMPAT_MODE
diff --git a/src/system/kernel/arch/x86/Jamfile
b/src/system/kernel/arch/x86/Jamfile
index fee9cbd..2489f7a 100644
--- a/src/system/kernel/arch/x86/Jamfile
+++ b/src/system/kernel/arch/x86/Jamfile
@@ -1,8 +1,5 @@
SubDir HAIKU_TOP src system kernel arch x86 ;
-SubDirHdrs [ FDirName
$(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH))
- system kernel ] ;
- # for syscall_numbers.h
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers ps2 ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include
@@ -15,6 +12,10 @@
SEARCH_SOURCE += [ FDirName $(SUBDIR) paging ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) timers ] ;
+ObjectHdrs interrupts.S signals.cpp signals_asm.S : [ FDirName
+ $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) system
kernel ] ;
+ # for syscall_numbers.h
+
local archSpecificSources ;
if $(TARGET_ARCH) = x86_64 {
SEARCH_SOURCE += [ FDirName $(SUBDIR) 64 ] ;
@@ -29,6 +30,7 @@
signals.cpp
signals_asm.S
syscalls.cpp
+ syscalls_asm.S
thread.cpp
# paging
@@ -39,6 +41,17 @@
X86PagingStructures64Bit.cpp
X86VMTranslationMap64Bit.cpp
;
+
+ if $(HAIKU_KERNEL_COMPAT_MODE) = 1 {
+ archSpecificSources +=
+ arch_commpage_compat.cpp
+ arch_elf_compat.cpp
+ entry_compat.S
+ syscalls_compat.cpp
+ signals_compat_asm.S
+ signals_compat.cpp
+ ;
+ }
} else {
SEARCH_SOURCE += [ FDirName $(SUBDIR) 32 ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) paging 32bit ] ;
@@ -121,3 +134,15 @@
: <syscalls!$(TARGET_PACKAGING_ARCH)>syscall_numbers.h ;
Includes [ FGristFiles interrupts.S ]
: <syscalls!$(TARGET_PACKAGING_ARCH)>syscall_table.h ;
+
+if $(TARGET_ARCH) = x86_64 && $(HAIKU_KERNEL_COMPAT_MODE) = 1 {
+ ObjectHdrs entry_compat.S syscalls_compat.cpp : [ FDirName
+ $(TARGET_COMMON_DEBUG_OBJECT_DIR_x86) system kernel ] ;
+ # for syscall_numbers.h
+
+ # We need to specify the dependency on the generated syscalls file
explicitly.
+ Includes [ FGristFiles entry_compat.S ]
+ : <syscalls!x86>syscall_numbers.h ;
+ Includes [ FGristFiles entry_compat.S syscalls_compat.cpp ]
+ : <syscalls!x86>syscall_table.h ;
+}
diff --git a/src/system/kernel/arch/x86/arch_debug.cpp
b/src/system/kernel/arch/x86/arch_debug.cpp
index 2ab6b2e..00566bb 100644
--- a/src/system/kernel/arch/x86/arch_debug.cpp
+++ b/src/system/kernel/arch/x86/arch_debug.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright 2018, Jérôme Duval, jerome.duval@xxxxxxxxx.
* Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@xxxxxx.
* Copyright 2002-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
* Copyright 2012, Alex Smith, alex@xxxxxxxxxxxxxxxx.
@@ -35,6 +36,20 @@
addr_t return_address;
};
+
+#ifdef _COMPAT_MODE
+
+
+typedef uint32 compat_addr_t;
+struct compat_stack_frame {
+ compat_addr_t previous;
+ compat_addr_t return_address;
+};
+
+
+#endif // _COMPAT_MODE
+
+
#define NUM_PREVIOUS_LOCATIONS 32
@@ -102,6 +117,28 @@
}
+#ifdef _COMPAT_MODE
+
+
+/*! Safe to be called only from inside the debugger.
+*/
+static status_t
+compat_get_next_frame_debugger(addr_t bp, addr_t* _next, addr_t* _ip)
+{
+ compat_stack_frame frame;
+ if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)bp, sizeof(frame)) !=
B_OK)
+ return B_BAD_ADDRESS;
+
+ *_ip = (addr_t)frame.return_address;
+ *_next = (addr_t)frame.previous;
+
+ return B_OK;
+}
+
+
+#endif // _COMPAT_MODE
+
+
static status_t
lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress,
const char** _symbolName, const char** _imageName, bool* _exactMatch)
@@ -377,7 +414,7 @@
const char* image;
addr_t baseAddress;
bool exactMatch;
- status_t status;
+ status_t status = B_ERROR;
addr_t diff;
diff = nextBp - bp;
@@ -386,8 +423,18 @@
if (diff & ~((addr_t)-1 >> 1))
diff = 0;
+#ifdef _COMPAT_MODE
+ // only lookup kernel symbols in compatibility mode
+ // TODO: support lookup user symbols in compatibility mode
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) == 0
+ || IS_KERNEL_ADDRESS(ip)) {
+ status = lookup_symbol(thread, ip, &baseAddress, &symbol,
&image,
+ &exactMatch);
+ }
+#else
status = lookup_symbol(thread, ip, &baseAddress, &symbol, &image,
&exactMatch);
+#endif
kprintf("%2" B_PRId32 " %0*lx (+%4ld) %0*lx ", callIndex,
B_PRINTF_POINTER_WIDTH, bp, diff, B_PRINTF_POINTER_WIDTH, ip);
@@ -726,6 +773,16 @@
} else {
addr_t ip, nextBp;
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0
+ && !is_kernel_stack_address(thread, bp)) {
+ if (compat_get_next_frame_debugger(bp, &nextBp,
&ip) != B_OK) {
+ kprintf("%0*lx -- read fault\n",
B_PRINTF_POINTER_WIDTH,
+ bp);
+ break;
+ }
+ } else
+#endif
if (get_next_frame_debugger(bp, &nextBp, &ip) != B_OK) {
kprintf("%0*lx -- read fault\n",
B_PRINTF_POINTER_WIDTH, bp);
break;
diff --git a/src/system/kernel/arch/x86/arch_thread.cpp
b/src/system/kernel/arch/x86/arch_thread.cpp
index 931c74b..598c024 100644
--- a/src/system/kernel/arch/x86/arch_thread.cpp
+++ b/src/system/kernel/arch/x86/arch_thread.cpp
@@ -192,6 +192,23 @@
status_t
arch_thread_init_tls(Thread* thread)
{
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ uint32 tls[TLS_FIRST_FREE_SLOT];
+
+ thread->user_local_storage = thread->user_stack_base
+ + thread->user_stack_size;
+
+ // initialize default TLS fields
+ memset(tls, 0, sizeof(tls));
+ tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage;
+ tls[TLS_THREAD_ID_SLOT] = thread->id;
+ tls[TLS_USER_THREAD_SLOT] = (uint32)(addr_t)thread->user_thread;
+
+ return user_memcpy((void*)thread->user_local_storage, tls,
sizeof(tls));
+ }
+#endif
+
addr_t tls[TLS_FIRST_FREE_SLOT];
thread->user_local_storage = thread->user_stack_base
diff --git a/src/system/kernel/debug/Jamfile b/src/system/kernel/debug/Jamfile
index 6b17975..2fcc0b7 100644
--- a/src/system/kernel/debug/Jamfile
+++ b/src/system/kernel/debug/Jamfile
@@ -7,6 +7,9 @@
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) device_manager ] ;
+if $(HAIKU_KERNEL_COMPAT_MODE) = 1 {
+ UsePrivateHeaders [ FDirName kernel compat ] ;
+}
KernelMergeObject kernel_debug.o :
blue_screen.cpp
diff --git a/src/system/kernel/debug/safemode_settings.cpp
b/src/system/kernel/debug/safemode_settings.cpp
index c0a6ca6..076718c 100644
--- a/src/system/kernel/debug/safemode_settings.cpp
+++ b/src/system/kernel/debug/safemode_settings.cpp
@@ -17,11 +17,17 @@
#include <boot/kernel_args.h>
#include <kernel.h>
#include <syscalls.h>
+#include <util/syscall_args.h>
#ifndef _BOOT_MODE
+#ifdef _COMPAT_MODE
+# include <OS_compat.h>
+#endif
+
+
static status_t
get_option_from_kernel_args(kernel_args* args, const char* settingsName,
const char* parameter, size_t parameterLength, char* buffer,
@@ -255,22 +261,24 @@
size_t bufferSize, originalBufferSize;
if (!IS_USER_ADDRESS(userParameter) || !IS_USER_ADDRESS(userBuffer)
- || !IS_USER_ADDRESS(_userBufferSize)
- || user_memcpy(&bufferSize, _userBufferSize, sizeof(size_t)) !=
B_OK
|| user_strlcpy(parameter, userParameter, B_FILE_NAME_LENGTH) <
B_OK)
return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(_userBufferSize, bufferSize);
+ if (status != B_OK)
+ return status;
+
if (bufferSize > B_PATH_NAME_LENGTH)
bufferSize = B_PATH_NAME_LENGTH;
originalBufferSize = bufferSize;
- status_t status = get_safemode_option(parameter, buffer, &bufferSize);
+ status = get_safemode_option(parameter, buffer, &bufferSize);
- if (status == B_OK
- && (user_strlcpy(userBuffer, buffer, originalBufferSize) < B_OK
- || user_memcpy(_userBufferSize, &bufferSize,
sizeof(size_t))
- != B_OK))
- return B_BAD_ADDRESS;
+ if (status == B_OK) {
+ if (user_strlcpy(userBuffer, buffer, originalBufferSize) < B_OK)
+ return B_BAD_ADDRESS;
+ status = copy_ref_var_to_user(bufferSize, _userBufferSize);
+ }
return status;
}
diff --git a/src/system/kernel/disk_device_manager/Jamfile
b/src/system/kernel/disk_device_manager/Jamfile
index 5841470..9a92649 100644
--- a/src/system/kernel/disk_device_manager/Jamfile
+++ b/src/system/kernel/disk_device_manager/Jamfile
@@ -12,6 +12,10 @@
UsePrivateHeaders shared ;
UsePrivateHeaders storage ;
+if $(HAIKU_KERNEL_COMPAT_MODE) = 1 {
+ UsePrivateHeaders [ FDirName kernel compat ] ;
+}
+
KernelMergeObject kernel_disk_device_manager.o :
ddm_userland_interface.cpp
disk_device_manager.cpp
diff --git a/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp
b/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp
index db4e696..730d672 100644
--- a/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp
+++ b/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp
@@ -25,6 +25,10 @@
#include <KFileDiskDevice.h>
#include <syscall_args.h>
+#ifdef _COMPAT_MODE
+# include <OS_compat.h>
+#endif
+
#include "UserDataWriter.h"
using namespace BPrivate::DiskDevice;
diff --git a/src/system/kernel/fs/Jamfile b/src/system/kernel/fs/Jamfile
index d2d0f84..10f6fd7 100644
--- a/src/system/kernel/fs/Jamfile
+++ b/src/system/kernel/fs/Jamfile
@@ -7,6 +7,10 @@
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) device_manager ] ;
+if $(HAIKU_KERNEL_COMPAT_MODE) = 1 {
+ UsePrivateHeaders [ FDirName kernel compat ] ;
+}
+
KernelMergeObject kernel_fs.o :
EntryCache.cpp
fd.cpp
diff --git a/src/system/kernel/fs/socket.cpp b/src/system/kernel/fs/socket.cpp
index e4c02f4..6e23e02 100644
--- a/src/system/kernel/fs/socket.cpp
+++ b/src/system/kernel/fs/socket.cpp
@@ -22,8 +22,13 @@
#include <lock.h>
#include <syscall_restart.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
#include <vfs.h>
+#ifdef _COMPAT_MODE
+# include <socket_compat.h>
+#endif
+
#include <net_stack_interface.h>
#include <net_stat.h>
@@ -149,10 +154,9 @@
return B_BAD_VALUE;
// copy message from userland
- if (!IS_USER_ADDRESS(userMessage)
- || user_memcpy(&message, userMessage, sizeof(msghdr))
!= B_OK) {
- return B_BAD_ADDRESS;
- }
+ status_t status = copy_ref_var_from_user((msghdr*)userMessage, message);
+ if (status != B_OK)
+ return status;
userVecs = message.msg_iov;
userAddress = message.msg_name;
diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp
index f3d8ca2..80a1604 100644
--- a/src/system/kernel/fs/vfs.cpp
+++ b/src/system/kernel/fs/vfs.cpp
@@ -52,11 +52,21 @@
#include <util/atomic.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
+#include <util/syscall_args.h>
#include <vfs.h>
#include <vm/vm.h>
#include <vm/VMCache.h>
#include <wait_for_objects.h>
+#ifdef _COMPAT_MODE
+# include <fcntl_compat.h>
+# include <stat_compat.h>
+# include <fs_attr_compat.h>
+# include <fs_info_compat.h>
+# include <OS_compat.h>
+# include <vfs_defs_compat.h>
+#endif
+
#include "EntryCache.h"
#include "fifo.h"
#include "IORequest.h"
@@ -6206,9 +6216,8 @@
status = B_BAD_VALUE;
else if (kernel)
memcpy(&flock, (struct flock*)argument, sizeof(struct
flock));
- else if (user_memcpy(&flock, (struct flock*)argument,
- sizeof(struct flock)) != B_OK)
- status = B_BAD_ADDRESS;
+ else
+ status = copy_ref_var_from_user((struct
flock*)argument, flock);
if (status != B_OK) {
put_fd(descriptor);
return status;
@@ -6301,8 +6310,8 @@
memcpy((struct
flock*)argument, &flock,
sizeof(struct
flock));
} else {
- status =
user_memcpy((struct flock*)argument,
- &flock,
sizeof(struct flock));
+ status =
copy_ref_var_to_user(flock,
+ (struct
flock*)argument);
}
} else {
// a conflicting lock was
found, copy back its range and
@@ -6314,8 +6323,8 @@
memcpy((struct
flock*)argument,
&normalizedLock, sizeof(struct flock));
} else {
- status =
user_memcpy((struct flock*)argument,
-
&normalizedLock, sizeof(struct flock));
+ status =
copy_ref_var_to_user(normalizedLock,
+ (struct
flock*)argument);
}
}
}
@@ -8929,10 +8938,7 @@
if (status != B_OK)
return status;
- if (user_memcpy(userInfo, &info, sizeof(struct fs_info)) != B_OK)
- return B_BAD_ADDRESS;
-
- return B_OK;
+ return copy_ref_var_to_user(info, userInfo);
}
@@ -8944,9 +8950,9 @@
if (userInfo == NULL)
return B_BAD_VALUE;
- if (!IS_USER_ADDRESS(userInfo)
- || user_memcpy(&info, userInfo, sizeof(struct fs_info)) != B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user((struct fs_info*)userInfo,
info);
+ if (status != B_OK)
+ return status;
return fs_write_info(device, &info, mask);
}
@@ -8992,9 +8998,6 @@
if (geteuid() != 0)
return B_NOT_ALLOWED;
- if (infoSize != sizeof(fd_info))
- return B_BAD_VALUE;
-
if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
|| user_memcpy(&cookie, userCookie, sizeof(uint32)) != B_OK)
return B_BAD_ADDRESS;
@@ -9003,11 +9006,9 @@
if (status != B_OK)
return status;
- if (user_memcpy(userCookie, &cookie, sizeof(uint32)) != B_OK
- || user_memcpy(userInfo, &info, infoSize) != B_OK)
+ if (user_memcpy(userCookie, &cookie, sizeof(uint32)) != B_OK)
return B_BAD_ADDRESS;
-
- return status;
+ return copy_ref_var_to_user(info, userInfo);
}
@@ -9385,12 +9386,14 @@
if (pathBuffer.InitCheck() != B_OK || linkBuffer.InitCheck() != B_OK)
return B_NO_MEMORY;
- size_t bufferSize;
-
- if (!IS_USER_ADDRESS(userBuffer) || !IS_USER_ADDRESS(userBufferSize)
- || user_memcpy(&bufferSize, userBufferSize, sizeof(size_t)) !=
B_OK)
+ if (!IS_USER_ADDRESS(userBuffer))
return B_BAD_ADDRESS;
+ size_t bufferSize;
+ status_t copyStatus = copy_ref_var_from_user(userBufferSize,
bufferSize);
+ if (copyStatus != B_OK)
+ return copyStatus;
+
char* path = pathBuffer.LockBuffer();
char* buffer = linkBuffer.LockBuffer();
@@ -9411,8 +9414,9 @@
// we also update the bufferSize in case of errors
// (the real length will be returned in case of B_BUFFER_OVERFLOW)
- if (user_memcpy(userBufferSize, &newBufferSize, sizeof(size_t)) != B_OK)
- return B_BAD_ADDRESS;
+ copyStatus = copy_ref_var_to_user(bufferSize, userBufferSize);
+ if (copyStatus != B_OK)
+ return copyStatus;
if (status != B_OK)
return status;
@@ -9686,7 +9690,7 @@
if (status != B_OK)
return status;
- return user_memcpy(userStat, &stat, statSize);
+ return copy_ref_var_to_user(stat, userStat, statSize);
}
@@ -9699,16 +9703,15 @@
struct stat stat;
- if (!IS_USER_ADDRESS(userStat)
- || user_memcpy(&stat, userStat, statSize) < B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user((struct stat*)userStat, stat,
+ statSize);
+ if (status != B_OK)
+ return status;
// clear additional stat fields
if (statSize < sizeof(struct stat))
memset((uint8*)&stat + statSize, 0, sizeof(struct stat) -
statSize);
- status_t status;
-
if (userPath != NULL) {
// path given: write the stat of the node referred to by (fd,
path)
if (!IS_USER_ADDRESS(userPath))
@@ -9860,8 +9863,7 @@
info.type = stat.st_type;
info.size = stat.st_size;
- if (user_memcpy(userAttrInfo, &info, sizeof(struct attr_info))
!= B_OK)
- return B_BAD_ADDRESS;
+ status = copy_ref_var_to_user(info, userAttrInfo);
}
return status;
@@ -9982,10 +9984,8 @@
return status;
status = index_name_read_stat(device, name, &stat, false);
- if (status == B_OK) {
- if (user_memcpy(userStat, &stat, sizeof(stat)) != B_OK)
- return B_BAD_ADDRESS;
- }
+ if (status == B_OK)
+ status = copy_ref_var_to_user(stat, userStat);
return status;
}
diff --git a/src/system/kernel/image.cpp b/src/system/kernel/image.cpp
index 3fb9b72..d91ca10 100644
--- a/src/system/kernel/image.cpp
+++ b/src/system/kernel/image.cpp
@@ -18,6 +18,11 @@
#include <thread_types.h>
#include <user_debugger.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
+
+#ifdef _COMPAT_MODE
+# include <image_compat.h>
+#endif
#include <stdlib.h>
#include <string.h>
@@ -463,12 +468,9 @@
{
extended_image_info info;
- if (size != sizeof(info))
- return B_BAD_VALUE;
-
- if (!IS_USER_ADDRESS(userInfo)
- || user_memcpy(&info, userInfo, size) < B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userInfo, info, size);
+ if (status != B_OK)
+ return status;
return register_image(thread_get_current_thread()->team, &info, size);
}
@@ -524,9 +526,9 @@
status = _get_image_info(id, &info, sizeof(image_info));
- if (user_memcpy(userInfo, &info, size) < B_OK)
- return B_BAD_ADDRESS;
-
+ status_t err = copy_ref_var_to_user(info, userInfo, size);
+ if (err != B_OK)
+ return err;
return status;
}
@@ -539,9 +541,6 @@
status_t status;
int32 cookie;
- if (size > sizeof(image_info))
- return B_BAD_VALUE;
-
if (!IS_USER_ADDRESS(userInfo) || !IS_USER_ADDRESS(_cookie)
|| user_memcpy(&cookie, _cookie, sizeof(int32)) < B_OK) {
return B_BAD_ADDRESS;
@@ -549,10 +548,11 @@
status = _get_next_image_info(team, &cookie, &info, sizeof(image_info));
- if (user_memcpy(userInfo, &info, size) < B_OK
- || user_memcpy(_cookie, &cookie, sizeof(int32)) < B_OK) {
+ status_t err = copy_ref_var_to_user(info, userInfo, size);
+ if (err != B_OK)
+ return err;
+ if (user_memcpy(_cookie, &cookie, sizeof(int32)) < B_OK)
return B_BAD_ADDRESS;
- }
return status;
}
diff --git a/src/system/kernel/signal.cpp b/src/system/kernel/signal.cpp
index cea1c31..f0a6710 100644
--- a/src/system/kernel/signal.cpp
+++ b/src/system/kernel/signal.cpp
@@ -35,6 +35,11 @@
#include <user_debugger.h>
#include <user_thread.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
+
+#ifdef _COMPAT_MODE
+# include <compat/ksignal_compat.h>
+#endif
//#define TRACE_SIGNAL
@@ -908,6 +913,61 @@
}
+#ifdef _COMPAT_MODE
+
+static status_t
+setup_compat_signal_frame(Thread* thread, struct sigaction* action, Signal*
signal,
+ sigset_t signalMask)
+{
+ // prepare the data, we need to copy onto the user stack
+ struct compat_signal_frame_data frameData;
+
+ // signal info
+ frameData.info.si_signo = signal->Number();
+ frameData.info.si_code = signal->SignalCode();
+ frameData.info.si_errno = signal->ErrorCode();
+ frameData.info.si_pid = signal->SendingProcess();
+ frameData.info.si_uid = signal->SendingUser();
+ frameData.info.si_addr = (addr_t)signal->Address();
+ frameData.info.si_status = signal->Status();
+ frameData.info.si_band = signal->PollBand();
+ frameData.info.si_value.sival_ptr =
(addr_t)signal->UserValue().sival_ptr;
+
+ // context
+ frameData.context.uc_link = (addr_t)thread->user_signal_context;
+ frameData.context.uc_sigmask = signalMask;
+ // uc_stack and uc_mcontext are filled in by the architecture specific
code.
+
+ // user data
+ frameData.user_data = (addr_t)action->sa_userdata;
+
+ // handler function
+ frameData.siginfo_handler = (action->sa_flags & SA_SIGINFO) != 0;
+ frameData.handler = frameData.siginfo_handler
+ ? (addr_t)action->sa_sigaction : (addr_t)action->sa_handler;
+
+ // thread flags -- save the and clear the thread's syscall restart
related
+ // flags
+ frameData.thread_flags = atomic_and(&thread->flags,
+ ~(THREAD_FLAGS_RESTART_SYSCALL |
THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
+
+ // syscall restart related fields
+ memcpy(frameData.syscall_restart_parameters,
+ thread->syscall_restart.parameters,
+ sizeof(frameData.syscall_restart_parameters));
+
+ // commpage address
+ frameData.commpage_address = (addr_t)thread->team->commpage_address;
+
+ // syscall_restart_return_value is filled in by the architecture
specific
+ // code.
+
+ return arch_setup_compat_signal_frame(thread, action, &frameData);
+}
+
+#endif // _COMPAT_MODE
+
+
/*! Actually handles pending signals -- i.e. the thread will exit, a custom
signal handler is prepared, or whatever the signal demands.
The function will not return, when a deadly signal is encountered. The
@@ -1258,6 +1318,11 @@
locker.Unlock();
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
+ setup_compat_signal_frame(thread, &handler, signal,
oldBlockMask);
+ else
+#endif
setup_signal_frame(thread, &handler, signal, oldBlockMask);
// Reset sigsuspend_original_unblocked_mask. It would have been
set by
@@ -2235,11 +2300,10 @@
// Copy the user value from userland. If not given, use a dummy value.
union sigval userValue;
if (userUserValue != NULL) {
- if (!IS_USER_ADDRESS(userUserValue)
- || user_memcpy(&userValue, userUserValue,
sizeof(userValue))
- != B_OK) {
- return B_BAD_ADDRESS;
- }
+ status_t status = copy_ref_var_from_user((union
sigval*)userUserValue,
+ userValue);
+ if (status != B_OK)
+ return status;
} else
userValue.sival_ptr = NULL;
@@ -2296,20 +2360,23 @@
struct sigaction act, oact;
status_t status;
- if ((userAction != NULL && (!IS_USER_ADDRESS(userAction)
- || user_memcpy(&act, userAction, sizeof(struct
sigaction)) < B_OK))
- || (userOldAction != NULL && (!IS_USER_ADDRESS(userOldAction)
- || user_memcpy(&oact, userOldAction, sizeof(struct
sigaction))
- < B_OK)))
- return B_BAD_ADDRESS;
+ if (userAction != NULL) {
+ status = copy_ref_var_from_user((struct sigaction*)userAction,
act);
+ if (status < B_OK)
+ return status;
+ }
+ if (userOldAction != NULL) {
+ status = copy_ref_var_from_user(userOldAction, oact);
+ if (status < B_OK)
+ return status;
+ }
status = sigaction_internal(signal, userAction ? &act : NULL,
userOldAction ? &oact : NULL);
// only copy the old action if a pointer has been given
- if (status >= B_OK && userOldAction != NULL
- && user_memcpy(userOldAction, &oact, sizeof(struct sigaction))
< B_OK)
- return B_BAD_ADDRESS;
+ if (status >= B_OK && userOldAction != NULL)
+ status = copy_ref_var_to_user(oact, userOldAction);
return status;
}
@@ -2339,7 +2406,7 @@
if (status == B_OK) {
// copy the info back to userland, if userSet is non-NULL
if (userInfo != NULL)
- status = user_memcpy(userInfo, &info, sizeof(info));
+ status = copy_ref_var_to_user(info, userInfo);
} else if (status == B_INTERRUPTED) {
// make sure we'll be restarted
Thread* thread = thread_get_current_thread();
@@ -2393,11 +2460,17 @@
struct stack_t newStack, oldStack;
bool onStack = false;
- if ((newUserStack != NULL && (!IS_USER_ADDRESS(newUserStack)
- || user_memcpy(&newStack, newUserStack,
sizeof(stack_t)) < B_OK))
- || (oldUserStack != NULL && (!IS_USER_ADDRESS(oldUserStack)
- || user_memcpy(&oldStack, oldUserStack,
sizeof(stack_t)) < B_OK)))
- return B_BAD_ADDRESS;
+ if (newUserStack != NULL) {
+ status_t status = copy_ref_var_from_user((stack_t*)newUserStack,
+ newStack);
+ if (status < B_OK)
+ return status;
+ }
+ if (oldUserStack != NULL) {
+ status_t status = copy_ref_var_from_user(oldUserStack,
oldStack);
+ if (status < B_OK)
+ return status;
+ }
if (thread->signal_stack_enabled) {
// determine whether or not the user thread is currently
@@ -2434,9 +2507,8 @@
}
// only copy the old stack info if a pointer has been given
- if (oldUserStack != NULL
- && user_memcpy(oldUserStack, &oldStack, sizeof(stack_t)) < B_OK)
- return B_BAD_ADDRESS;
+ if (oldUserStack != NULL)
+ return copy_ref_var_to_user(oldStack, oldUserStack);
return B_OK;
}
@@ -2470,6 +2542,54 @@
Thread *thread = thread_get_current_thread();
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ // copy the signal frame data from userland
+ compat_signal_frame_data signalFrameData;
+ if (userSignalFrameData == NULL ||
!IS_USER_ADDRESS(userSignalFrameData)
+ || user_memcpy(&signalFrameData, userSignalFrameData,
+ sizeof(signalFrameData)) != B_OK) {
+ // We failed to copy the signal frame data from
userland. This is a
+ // serious problem. Kill the thread.
+ dprintf("_user_restore_signal_frame(): thread %"
B_PRId32 ": Failed to "
+ "copy signal frame data (%p) from userland.
Killing thread...\n",
+ thread->id, userSignalFrameData);
+ kill_thread(thread->id);
+ return B_BAD_ADDRESS;
+ }
+
+ // restore the signal block mask
+ InterruptsSpinLocker locker(thread->team->signal_lock);
+
+ thread->sig_block_mask
+ = signalFrameData.context.uc_sigmask &
BLOCKABLE_SIGNALS;
+ update_current_thread_signals_flag();
+
+ locker.Unlock();
+
+ // restore the syscall restart related thread flags and the
syscall restart
+ // parameters
+ atomic_and(&thread->flags,
+ ~(THREAD_FLAGS_RESTART_SYSCALL |
THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
+ atomic_or(&thread->flags, signalFrameData.thread_flags
+ & (THREAD_FLAGS_RESTART_SYSCALL |
THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
+
+ memcpy(thread->syscall_restart.parameters,
+ signalFrameData.syscall_restart_parameters,
+ sizeof(thread->syscall_restart.parameters));
+
+ // restore the previously stored Thread::user_signal_context
+ thread->user_signal_context =
(ucontext_t*)(addr_t)signalFrameData.context.uc_link;
+ if (thread->user_signal_context != NULL
+ && !IS_USER_ADDRESS(thread->user_signal_context)) {
+ thread->user_signal_context = NULL;
+ }
+
+ // let the architecture specific code restore the registers
+ return arch_restore_compat_signal_frame(&signalFrameData);
+ }
+#endif
+
// copy the signal frame data from userland
signal_frame_data signalFrameData;
if (userSignalFrameData == NULL || !IS_USER_ADDRESS(userSignalFrameData)
diff --git a/src/system/kernel/system_info.cpp
b/src/system/kernel/system_info.cpp
index 6b7ea50..64dab4a 100644
--- a/src/system/kernel/system_info.cpp
+++ b/src/system/kernel/system_info.cpp
@@ -31,6 +31,9 @@
#include <lock.h>
#include <Notifications.h>
#include <messaging.h>
+#ifdef _COMPAT_MODE
+# include <OS_compat.h>
+#endif
#include <port.h>
#include <real_time_clock.h>
#include <sem.h>
@@ -38,6 +41,7 @@
#include <team.h>
#include <thread.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
@@ -561,13 +565,8 @@
system_info info;
status_t status = get_system_info(&info);
- if (status == B_OK) {
- if (user_memcpy(userInfo, &info, sizeof(system_info)) < B_OK)
- return B_BAD_ADDRESS;
-
- return B_OK;
- }
-
+ if (status == B_OK)
+ return copy_ref_var_to_user(info, userInfo);
return status;
}
diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp
index ec5339a..471cdd8 100644
--- a/src/system/kernel/team.cpp
+++ b/src/system/kernel/team.cpp
@@ -58,6 +58,13 @@
#include <vm/vm.h>
#include <vm/VMAddressSpace.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
+
+#ifdef _COMPAT_MODE
+# include <commpage_compat.h>
+# include <OS_compat.h>
+# include <signal_compat.h>
+#endif
#include "TeamThreadTables.h"
@@ -87,6 +94,7 @@
};
#define TEAM_ARGS_FLAG_NO_ASLR 0x01
+#define TEAM_ARGS_FLAG_COMPAT_FLATARGS 0x02
namespace {
@@ -1348,7 +1356,8 @@
static status_t
-create_team_user_data(Team* team, void* exactAddress = NULL)
+create_team_user_data(Team* team, void* exactAddress = NULL,
+ void* baseAddress = NULL)
{
void* address;
uint32 addressSpec;
@@ -1357,7 +1366,8 @@
address = exactAddress;
addressSpec = B_EXACT_ADDRESS;
} else {
- address = (void*)KERNEL_USER_DATA_BASE;
+ address = baseAddress != NULL ? baseAddress
+ : (void*)KERNEL_USER_DATA_BASE;
addressSpec = B_RANDOMIZED_BASE_ADDRESS;
}
@@ -1372,7 +1382,8 @@
virtualRestrictions.address = address;
virtualRestrictions.address_specification = B_EXACT_ADDRESS;
} else {
- virtualRestrictions.address = (void*)KERNEL_USER_DATA_BASE;
+ virtualRestrictions.address = baseAddress != NULL ? baseAddress
+ : (void*)KERNEL_USER_DATA_BASE;
virtualRestrictions.address_specification =
B_RANDOMIZED_BASE_ADDRESS;
}
@@ -1517,6 +1528,12 @@
}
}
+#ifdef _COMPAT_MODE
+ Thread* thread = thread_get_current_thread();
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
+ teamArg->flags |= TEAM_ARGS_FLAG_COMPAT_FLATARGS;
+#endif
+
*_teamArg = teamArg;
return B_OK;
}
@@ -1567,17 +1584,119 @@
userEnv = userArgs + argCount + 1;
path = teamArgs->path;
+ // set team args and update state
+ // TODO: this can't work with a compat flat_args
+ team->Lock();
+ team->SetArgs(path, teamArgs->flat_args + 1, argCount - 1);
+ team->state = TEAM_STATE_NORMAL;
+ team->Unlock();
+
+#ifdef _COMPAT_MODE
+ // in compat mode, userArgs and userEnv should only be uint32
+ if ((teamArgs->flags & TEAM_ARGS_FLAG_COMPAT_FLATARGS) == 0
+ && (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ // now make the arrays 32-bits wide
+ addr_t pointerOffset = 4; // sizeof(addr_t) - sizeof(uint32)
+ size_t pointerSize = sizeof(uint32);
+ uint32 *elfArgs = (uint32*)teamArgs->flat_args;
+ addr_t *tempArgs = (addr_t*)teamArgs->flat_args;
+ if (argCount > 0) {
+ for (int i = 0; i < argCount; i++) {
+ *elfArgs = (uint32)*tempArgs;
+ elfArgs++;
+ tempArgs++;
+ }
+ }
+ *elfArgs = NULL;
+ elfArgs++;
+ tempArgs++;
+ userEnv = (char**)elfArgs;
+ if (envCount > 0) {
+ for (int i = 0; i < envCount; i++) {
+ *elfArgs = (uint32)*tempArgs;
+ elfArgs++;
+ tempArgs++;
+ }
+ }
+ *elfArgs = NULL;
+
+ // now move the flat strings
+ size_t stringsOffset = (argCount + envCount + 2) *
sizeof(char*);
+ addr_t strings = (addr_t)teamArgs->flat_args + stringsOffset;
+ size_t strings32Offset = (argCount + envCount + 2) *
sizeof(uint32);
+ addr_t strings32 = (addr_t)teamArgs->flat_args +
strings32Offset;
+ memmove((void*)strings32, (void*)strings,
+ teamArgs->flat_args_size - stringsOffset);
+
+ uint32 user32Args = (uint32)(addr_t)userArgs;
+ uint32 user32Env = user32Args + (argCount + 1) * sizeof(uint32);
+ if (user_strlcpy(programArgs->program_path, path,
+ sizeof(programArgs->program_path)) <
B_OK
+ || user_memcpy(&programArgs->arg_count, &argCount,
sizeof(int32))
+ < B_OK
+ || user_memcpy(&programArgs->env_count, &envCount,
sizeof(int32))
+ < B_OK
+ || user_memcpy(&programArgs->args, &user32Args,
sizeof(user32Args))
+ < B_OK
+ || user_memcpy((void*)(((addr_t)&programArgs->args) +
4),
+ &user32Env, sizeof(user32Env)) < B_OK
+ || user_memcpy(&programArgs->error_port,
&teamArgs->error_port,
+ sizeof(port_id)) < B_OK
+ || user_memcpy(&programArgs->error_token,
&teamArgs->error_token,
+ sizeof(uint32)) < B_OK
+ || user_memcpy(&programArgs->umask, &teamArgs->umask,
+ sizeof(mode_t)) < B_OK
+ || user_memcpy(userArgs, teamArgs->flat_args,
+ teamArgs->flat_args_size -
(stringsOffset -
+ strings32Offset)) < B_OK) {
+ // the team deletion process will clean this mess
+ free_team_arg(teamArgs);
+ return B_BAD_ADDRESS;
+ }
+
+ } else if ((teamArgs->flags & TEAM_ARGS_FLAG_COMPAT_FLATARGS) != 0
+ && (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ uint32 user32Args = (uint32)(addr_t)userArgs;
+ uint32 user32Env = user32Args + (argCount + 1) * sizeof(uint32);
+
+ if (user_strlcpy(programArgs->program_path, path,
+ sizeof(programArgs->program_path)) < B_OK
+ || user_memcpy(&programArgs->arg_count, &argCount,
+ sizeof(int32)) < B_OK
+ || user_memcpy(&programArgs->args, &user32Args,
sizeof(uint32))
+ < B_OK
+ || user_memcpy(&programArgs->env_count, &envCount,
sizeof(int32))
+ < B_OK
+ || user_memcpy(&programArgs->env, &user32Env,
sizeof(uint32))
+ < B_OK
+ || user_memcpy(&programArgs->error_port,
&teamArgs->error_port,
+ sizeof(port_id)) < B_OK
+ || user_memcpy(&programArgs->error_token,
&teamArgs->error_token,
+ sizeof(uint32)) < B_OK
+ || user_memcpy(&programArgs->umask, &teamArgs->umask,
+ sizeof(mode_t)) < B_OK
+ || user_memcpy(userArgs, teamArgs->flat_args,
+ teamArgs->flat_args_size) < B_OK) {
+ // the team deletion process will clean this mess
+ free_team_arg(teamArgs);
+ return B_BAD_ADDRESS;
+ }
+ } else
+#endif
if (user_strlcpy(programArgs->program_path, path,
sizeof(programArgs->program_path)) < B_OK
- || user_memcpy(&programArgs->arg_count, &argCount,
sizeof(int32)) < B_OK
+ || user_memcpy(&programArgs->arg_count, &argCount,
sizeof(int32))
+ < B_OK
|| user_memcpy(&programArgs->args, &userArgs, sizeof(char**)) <
B_OK
- || user_memcpy(&programArgs->env_count, &envCount,
sizeof(int32)) < B_OK
+ || user_memcpy(&programArgs->env_count, &envCount,
sizeof(int32))
+ < B_OK
|| user_memcpy(&programArgs->env, &userEnv, sizeof(char**)) <
B_OK
|| user_memcpy(&programArgs->error_port, &teamArgs->error_port,
sizeof(port_id)) < B_OK
|| user_memcpy(&programArgs->error_token,
&teamArgs->error_token,
sizeof(uint32)) < B_OK
- || user_memcpy(&programArgs->umask, &teamArgs->umask,
sizeof(mode_t)) < B_OK
+ || user_memcpy(&programArgs->umask, &teamArgs->umask,
sizeof(mode_t))
+ < B_OK
|| user_memcpy(&programArgs->disable_user_addons,
&sDisableUserAddOns, sizeof(bool)) < B_OK
|| user_memcpy(userArgs, teamArgs->flat_args,
@@ -1589,19 +1708,23 @@
TRACE(("team_create_thread_start: loading elf binary '%s'\n", path));
- // set team args and update state
- team->Lock();
- team->SetArgs(path, teamArgs->flat_args + 1, argCount - 1);
- team->state = TEAM_STATE_NORMAL;
- team->Unlock();
-
free_team_arg(teamArgs);
// the arguments are already on the user stack, we no longer
need
// them in this form
// Clone commpage area
- area_id commPageArea = clone_commpage_area(team->id,
- &team->commpage_address);
+ area_id commPageArea = -1;
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ team->commpage_address = (void*)KERNEL_USER32_DATA_BASE;
+ commPageArea = clone_commpage_compat_area(team->id,
+ &team->commpage_address);
+ } else
+#endif
+ {
+ team->commpage_address = (void*)KERNEL_USER_DATA_BASE;
+ commPageArea = clone_commpage_area(team->id,
&team->commpage_address);
+ }
if (commPageArea < B_OK) {
TRACE(("team_create_thread_start: clone_commpage_area() failed:
%s\n",
strerror(commPageArea)));
@@ -1642,11 +1765,21 @@
return err;
}
runtimeLoaderPath.UnlockBuffer();
- err = runtimeLoaderPath.Append("runtime_loader");
-
- if (err == B_OK) {
- err = elf_load_user_image(runtimeLoaderPath.Path(),
team, 0,
- &entry);
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ err = runtimeLoaderPath.Append("x86/runtime_loader");
+ if (err == B_OK) {
+ err =
elf32_load_user_image(runtimeLoaderPath.Path(), team, 0,
+ &entry);
+ }
+ } else
+#endif
+ {
+ err = runtimeLoaderPath.Append("runtime_loader");
+ if (err == B_OK) {
+ err =
elf_load_user_image(runtimeLoaderPath.Path(), team, 0,
+ &entry);
+ }
}
}
@@ -1691,6 +1824,8 @@
io_context* parentIOContext = NULL;
team_id teamID;
bool teamLimitReached = false;
+ void* kernelUserDataBase = (void*)KERNEL_USER_DATA_BASE;
+ size_t addressSpaceSize = USER_SIZE;
if (flatArgs == NULL || argCount == 0)
return B_BAD_VALUE;
@@ -1707,6 +1842,15 @@
else
threadName = path;
+#ifdef _COMPAT_MODE
+ bool isCompatMode = false;
+ KPath tmpFilePath;
+ if (tmpFilePath.SetTo(path, KPath::NORMALIZE) == B_OK) {
+ isCompatMode = (elf32_load_user_image(tmpFilePath.Path(), NULL,
+ ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE, NULL) == B_OK);
+ }
+#endif
+
// create the main thread object
Thread* mainThread;
status = Thread::Create(threadName, mainThread);
@@ -1714,6 +1858,14 @@
return status;
BReference<Thread> mainThreadReference(mainThread, true);
+#ifdef _COMPAT_MODE
+ if (isCompatMode) {
+ atomic_or(&mainThread->flags, THREAD_FLAGS_COMPAT_MODE);
+ kernelUserDataBase = (void*)KERNEL_USER32_DATA_BASE;
+ addressSpaceSize = USER32_SIZE;
+ }
+#endif
+
// create team object
Team* team = Team::Create(mainThread->id, path, false);
if (team == NULL)
@@ -1772,7 +1924,9 @@
vfs_exec_io_context(team->io_context);
// create an address space for this team
- status = VMAddressSpace::Create(team->id, USER_BASE, USER_SIZE, false,
+ // TODO: check the thread compat mode in an arch specific function
+ status = VMAddressSpace::Create(team->id, USER_BASE,
+ addressSpaceSize, false,
&team->address_space);
if (status != B_OK)
goto err2;
@@ -1781,7 +1935,7 @@
(teamArgs->flags & TEAM_ARGS_FLAG_NO_ASLR) == 0);
// create the user data area
- status = create_team_user_data(team);
+ status = create_team_user_data(team, NULL, kernelUserDataBase);
if (status != B_OK)
goto err4;
@@ -1907,6 +2061,7 @@
struct team_arg* teamArgs;
const char* threadName;
thread_id nubThreadID = -1;
+ void* kernelUserDataBase = (void*)KERNEL_USER_DATA_BASE;
TRACE(("exec_team(path = \"%s\", argc = %" B_PRId32 ", envCount = %"
B_PRId32 "): team %" B_PRId32 "\n", path, argCount, envCount,
@@ -1976,7 +2131,26 @@
team->address_space->SetRandomizingEnabled(
(teamArgs->flags & TEAM_ARGS_FLAG_NO_ASLR) == 0);
- status = create_team_user_data(team);
+ // cut the path from the team name and rename the main thread, too
+ threadName = strrchr(path, '/');
+ if (threadName != NULL)
+ threadName++;
+ else
+ threadName = path;
+#ifdef _COMPAT_MODE
+ bool isCompatMode = false;
+ KPath tmpFilePath;
+ if (tmpFilePath.SetTo(path, KPath::NORMALIZE) == B_OK) {
+ isCompatMode = (elf32_load_user_image(tmpFilePath.Path(), NULL,
+ ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE, NULL) == B_OK);
+ }
+
+ // user address space shouldn't have user areas left
+ team->address_space->SetSize(isCompatMode ? USER32_SIZE : USER_SIZE);
+ if (isCompatMode)
+ kernelUserDataBase = (void*)KERNEL_USER32_DATA_BASE;
+#endif
+ status = create_team_user_data(team, NULL, kernelUserDataBase);
if (status != B_OK) {
// creating the user data failed -- we're toast
free_team_arg(teamArgs);
@@ -1992,12 +2166,6 @@
team->SetName(path);
team->Unlock();
- // cut the path from the team name and rename the main thread, too
- threadName = strrchr(path, '/');
- if (threadName != NULL)
- threadName++;
- else
- threadName = path;
rename_thread(thread_get_current_thread_id(), threadName);
atomic_or(&team->flags, TEAM_FLAG_EXEC_DONE);
@@ -2016,8 +2184,13 @@
// cannot fail (the allocation for the team would have failed
already)
ThreadLocker currentThreadLocker(currentThread);
currentThread->user_thread = userThread;
+#ifdef _COMPAT_MODE
+ if (isCompatMode)
+ atomic_or(¤tThread->flags, THREAD_FLAGS_COMPAT_MODE);
+ else
+ atomic_and(¤tThread->flags, ~THREAD_FLAGS_COMPAT_MODE);
+#endif
currentThreadLocker.Unlock();
-
// create the user stack for the thread
status = thread_create_user_stack(currentThread->team, currentThread,
NULL,
0, sizeof(user_space_program_args) + teamArgs->flat_args_size);
@@ -3984,8 +4157,11 @@
return syscall_restart_handle_post(foundChild);
// copy info back to userland
- if (userInfo != NULL && user_memcpy(userInfo, &info, sizeof(info)) !=
B_OK)
- return B_BAD_ADDRESS;
+ if (userInfo != NULL) {
+ status_t status = copy_ref_var_to_user(info, userInfo);
+ if (status != B_OK)
+ return status;
+ }
// copy usage_info back to userland
if (usageInfo != NULL && user_memcpy(usageInfo, &usage_info,
sizeof(usage_info)) != B_OK) {
@@ -4460,8 +4636,9 @@
// copy the needed size and, if it fits, the message back to userland
size_t sizeNeeded = info.ContentSize();
- if (user_memcpy(_sizeNeeded, &sizeNeeded, sizeof(sizeNeeded)) != B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_to_user(sizeNeeded, _sizeNeeded);
+ if (status != B_OK)
+ return status;
if (sizeNeeded > size)
return B_BUFFER_OVERFLOW;
diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp
index 4ea3f60..38ff0e7 100644
--- a/src/system/kernel/thread.cpp
+++ b/src/system/kernel/thread.cpp
@@ -43,6 +43,7 @@
#include <syscall_restart.h>
#include <team.h>
#include <tls.h>
+#include <util/syscall_args.h>
#include <user_runtime.h>
#include <user_thread.h>
#include <vfs.h>
@@ -50,6 +51,12 @@
#include <vm/VMAddressSpace.h>
#include <wait_for_objects.h>
+#ifdef _COMPAT_MODE
+# include <OS_compat.h>
+# include <resource_compat.h>
+# include <thread_defs_compat.h>
+#endif
+
#include "TeamThreadTables.h"
@@ -552,11 +559,14 @@
ThreadCreationAttributes::InitFromUserAttributes(
const thread_creation_attributes* userAttributes, char* nameBuffer)
{
- if (userAttributes == NULL || !IS_USER_ADDRESS(userAttributes)
- || user_memcpy((thread_creation_attributes*)this,
userAttributes,
- sizeof(thread_creation_attributes)) != B_OK) {
+ if (userAttributes == NULL)
return B_BAD_ADDRESS;
- }
+
+ status_t status = copy_ref_var_from_user(
+ (BKernel::ThreadCreationAttributes*)userAttributes,
+ *this);
+ if (status != B_OK)
+ return status;
if (stack_size != 0
&& (stack_size < MIN_USER_STACK_SIZE
@@ -815,6 +825,10 @@
thread->name, thread->id);
stackBase = (uint8*)USER_STACK_REGION;
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
+ stackBase = (uint8*)USER32_STACK_REGION;
+#endif
virtual_address_restrictions virtualRestrictions = {};
virtualRestrictions.address_specification =
B_RANDOMIZED_BASE_ADDRESS;
@@ -900,6 +914,12 @@
(int32)THREAD_MAX_SET_PRIORITY);
thread->state = B_THREAD_SUSPENDED;
+#ifdef _COMPAT_MODE
+ Thread* currentThread = thread_get_current_thread();
+ if ((currentThread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
+ thread->flags |= THREAD_FLAGS_COMPAT_MODE;
+#endif
+
thread->sig_block_mask = attributes.signal_mask;
// init debug structure
@@ -3600,10 +3620,8 @@
status = _get_thread_info(id, &info, sizeof(thread_info));
- if (status >= B_OK
- && user_memcpy(userInfo, &info, sizeof(thread_info)) < B_OK)
- return B_BAD_ADDRESS;
-
+ if (status >= B_OK)
+ status = copy_ref_var_to_user(info, userInfo);
return status;
}
@@ -3624,11 +3642,9 @@
if (status < B_OK)
return status;
- if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
- || user_memcpy(userInfo, &info, sizeof(thread_info)) < B_OK)
+ if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK)
return B_BAD_ADDRESS;
-
- return status;
+ return copy_ref_var_to_user(info, userInfo);
}
@@ -3811,9 +3827,9 @@
ret = common_getrlimit(resource, &rl);
if (ret == 0) {
- ret = user_memcpy(urlp, &rl, sizeof(struct rlimit));
- if (ret < 0)
- return ret;
+ status_t status = copy_ref_var_to_user(rl, urlp);
+ if (status != B_OK)
+ return status;
return 0;
}
@@ -3830,10 +3846,10 @@
if (userResourceLimit == NULL)
return EINVAL;
- if (!IS_USER_ADDRESS(userResourceLimit)
- || user_memcpy(&resourceLimit, userResourceLimit,
- sizeof(struct rlimit)) < B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user((struct
rlimit*)userResourceLimit,
+ resourceLimit);
+ if (status != B_OK)
+ return status;
return common_setrlimit(resource, &resourceLimit);
}
diff --git a/src/system/kernel/vm/Jamfile b/src/system/kernel/vm/Jamfile
index c28480f..d597807 100644
--- a/src/system/kernel/vm/Jamfile
+++ b/src/system/kernel/vm/Jamfile
@@ -5,6 +5,9 @@
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) device_manager ] ;
UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
UsePrivateHeaders [ FDirName kernel util ] ;
+if $(HAIKU_KERNEL_COMPAT_MODE) = 1 {
+ UsePrivateHeaders [ FDirName kernel compat ] ;
+}
KernelMergeObject kernel_vm.o :
PageCacheLocker.cpp
diff --git a/src/system/kernel/vm/VMUserAddressSpace.cpp
b/src/system/kernel/vm/VMUserAddressSpace.cpp
index 4e302bc..2b7f73a 100644
--- a/src/system/kernel/vm/VMUserAddressSpace.cpp
+++ b/src/system/kernel/vm/VMUserAddressSpace.cpp
@@ -32,15 +32,6 @@
#endif
-#ifdef B_HAIKU_64_BIT
-const addr_t VMUserAddressSpace::kMaxRandomize =
0x8000000000ul;
-const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x20000000000ul;
-#else
-const addr_t VMUserAddressSpace::kMaxRandomize = 0x800000ul;
-const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x2000000ul;
-#endif
-
-
/*! Verifies that an area with the given aligned base and size fits into
the spot defined by base and limit and checks for overflows.
*/
@@ -85,6 +76,7 @@
VMAddressSpace(id, base, size, "address space"),
fNextInsertHint(0)
{
+ _SetMaxRandomize();
}
@@ -427,9 +419,9 @@
addr_t range = end - start + 1;
if (initial)
- range = std::min(range, kMaxInitialRandomize);
+ range = std::min(range, fMaxInitialRandomize);
else
- range = std::min(range, kMaxRandomize);
+ range = std::min(range, fMaxRandomize);
addr_t random = secure_get_random<addr_t>();
random %= range;
@@ -521,7 +513,6 @@
TRACE(("VMUserAddressSpace::_InsertAreaSlot: address space %p, start "
"0x%lx, size %ld, end 0x%lx, addressSpec %" B_PRIu32 ", area
%p\n",
this, start, size, end, addressSpec, area));
-
// do some sanity checking
if (start < fBase || size == 0 || end > fEndAddress
|| start + (size - 1) > end)
@@ -724,7 +715,7 @@
alignment);
addr_t startRange =
next->Base() + next->Size();
- startRange -= size +
kMaxRandomize;
+ startRange -= size +
fMaxRandomize;
startRange =
ROUNDDOWN(startRange, alignment);
startRange =
std::max(startRange, alignedNextBase);
diff --git a/src/system/kernel/vm/VMUserAddressSpace.h
b/src/system/kernel/vm/VMUserAddressSpace.h
index 8f9c918..2de8380 100644
--- a/src/system/kernel/vm/VMUserAddressSpace.h
+++ b/src/system/kernel/vm/VMUserAddressSpace.h
@@ -17,6 +17,10 @@
size_t
size);
virtual ~VMUserAddressSpace();
+ virtual void SetSize(size_t size) {
+
VMAddressSpace::SetSize(size);
+
_SetMaxRandomize(); }
+
virtual VMArea* FirstArea() const;
virtual VMArea* NextArea(VMArea* area) const;
@@ -56,8 +60,9 @@
private:
inline bool _IsRandomized(uint32
addressSpec) const;
- static addr_t _RandomizeAddress(addr_t start,
addr_t end,
+ addr_t
_RandomizeAddress(addr_t start, addr_t end,
size_t
alignment, bool initial = false);
+ inline void _SetMaxRandomize();
status_t
_InsertAreaIntoReservedRegion(addr_t start,
size_t
size, VMUserArea* area,
@@ -68,12 +73,27 @@
uint32
allocationFlags);
private:
- static const addr_t kMaxRandomize;
- static const addr_t kMaxInitialRandomize;
+ addr_t fMaxRandomize;
+ addr_t fMaxInitialRandomize;
VMUserAreaTree fAreas;
addr_t fNextInsertHint;
};
+inline void
+VMUserAddressSpace::_SetMaxRandomize()
+{
+#ifdef B_HAIKU_64_BIT
+ if (fEndAddress > UINT32_MAX) {
+ fMaxRandomize = 0x8000000000ul;
+ fMaxInitialRandomize = 0x20000000000ul;
+ return;
+ }
+#endif
+ fMaxRandomize = 0x800000ul;
+ fMaxInitialRandomize = 0x2000000ul;
+}
+
+
#endif /* VM_USER_ADDRESS_SPACE_H */
diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp
index c43a18f..439842c 100644
--- a/src/system/kernel/vm/vm.cpp
+++ b/src/system/kernel/vm/vm.cpp
@@ -47,12 +47,17 @@
#include <team.h>
#include <tracing.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
#include <vm/vm_page.h>
#include <vm/vm_priv.h>
#include <vm/VMAddressSpace.h>
#include <vm/VMArea.h>
#include <vm/VMCache.h>
+#ifdef _COMPAT_MODE
+# include <OS_compat.h>
+#endif
+
#include "VMAddressSpaceLocking.h"
#include "VMAnonymousCache.h"
#include "VMAnonymousNoSwapCache.h"
@@ -6057,6 +6062,44 @@
}
+#ifdef _COMPAT_MODE
+status_t
+_compat_get_next_area_info(team_id team, ssize_t* cookie, area_info* info,
size_t size)
+{
+ area_id nextID = *(area_id*)cookie;
+
+ // we're already through the list
+ if (nextID == (area_id)-1)
+ return B_ENTRY_NOT_FOUND;
+
+ if (team == B_CURRENT_TEAM)
+ team = team_get_current_team_id();
+
+ AddressSpaceReadLocker locker(team);
+ if (!locker.IsLocked())
+ return B_BAD_TEAM_ID;
+
+ VMArea* area;
+ for (VMAddressSpace::AreaIterator it
+ = locker.AddressSpace()->GetAreaIterator();
+ (area = it.Next()) != NULL;) {
+ if (area->id > nextID)
+ break;
+ }
+
+ if (area == NULL) {
+ nextID = (area_id)-1;
+ return B_ENTRY_NOT_FOUND;
+ }
+
+ fill_area_info(area, info, size);
+ *cookie = (ssize_t)(area->id);
+
+ return B_OK;
+}
+#endif
+
+
status_t
set_area_protection(area_id area, uint32 newProtection)
{
@@ -6194,23 +6237,22 @@
addr_t address;
- if (!IS_USER_ADDRESS(userAddress)
- || user_memcpy(&address, userAddress, sizeof(address)) != B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userAddress, address);
+ if (status != B_OK)
+ return status;
- status_t status = vm_reserve_address_range(
+ status = vm_reserve_address_range(
VMAddressSpace::CurrentID(), (void**)&address, addressSpec,
size,
RESERVED_AVOID_BASE);
if (status != B_OK)
return status;
- if (user_memcpy(userAddress, &address, sizeof(address)) != B_OK) {
+ status = copy_ref_var_to_user(address, userAddress);
+ if (status != B_OK) {
vm_unreserve_address_range(VMAddressSpace::CurrentID(),
(void*)address, size);
- return B_BAD_ADDRESS;
}
-
- return B_OK;
+ return status;
}
@@ -6256,10 +6298,8 @@
// TODO: do we want to prevent userland from seeing kernel protections?
//info.protection &= B_USER_PROTECTION;
- if (user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK)
- return B_BAD_ADDRESS;
+ return copy_ref_var_to_user(info, userInfo);
- return status;
}
@@ -6269,21 +6309,28 @@
ssize_t cookie;
if (!IS_USER_ADDRESS(userCookie)
- || !IS_USER_ADDRESS(userInfo)
- || user_memcpy(&cookie, userCookie, sizeof(ssize_t)) < B_OK)
+ || !IS_USER_ADDRESS(userInfo))
return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userCookie, cookie);
+ if (status != B_OK)
+ return status;
+
area_info info;
- status_t status = _get_next_area_info(team, &cookie, &info,
+#ifdef _COMPAT_MODE
+ status = _compat_get_next_area_info(team, &cookie, &info,
+#else
+ status = _get_next_area_info(team, &cookie, &info,
+#endif
sizeof(area_info));
if (status != B_OK)
return status;
//info.protection &= B_USER_PROTECTION;
- if (user_memcpy(userCookie, &cookie, sizeof(ssize_t)) < B_OK
- || user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK)
- return B_BAD_ADDRESS;
+ status = copy_ref_var_to_user(cookie, userCookie);
+ if (status == B_OK)
+ status = copy_ref_var_to_user(info, userInfo);
return status;
}
@@ -6321,16 +6368,17 @@
}
void* address;
- if (!IS_USER_ADDRESS(userAddress)
- || user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userAddress, address);
+ if (status != B_OK)
+ return status;
area_id newArea = transfer_area(area, &address, addressSpec, target,
false);
if (newArea < B_OK)
return newArea;
- if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK)
- return B_BAD_ADDRESS;
+ status = copy_ref_var_to_user(address, userAddress);
+ if (status != B_OK)
+ return status;
return newArea;
}
@@ -6353,11 +6401,13 @@
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(userName)
- || !IS_USER_ADDRESS(userAddress)
- || user_strlcpy(name, userName, sizeof(name)) < B_OK
- || user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
+ || user_strlcpy(name, userName, sizeof(name)) < B_OK)
return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userAddress, address);
+ if (status != B_OK)
+ return status;
+
fix_protection(&protection);
area_id clonedArea = vm_clone_area(VMAddressSpace::CurrentID(), name,
@@ -6366,9 +6416,10 @@
if (clonedArea < B_OK)
return clonedArea;
- if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
+ status = copy_ref_var_to_user(address, userAddress);
+ if (status < B_OK) {
delete_area(clonedArea);
- return B_BAD_ADDRESS;
+ return status;
}
return clonedArea;
@@ -6392,11 +6443,13 @@
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(userName)
- || !IS_USER_ADDRESS(userAddress)
- || user_strlcpy(name, userName, sizeof(name)) < B_OK
- || user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
+ || user_strlcpy(name, userName, sizeof(name)) < B_OK)
return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userAddress, address);
+ if (status != B_OK)
+ return status;
+
if (addressSpec == B_EXACT_ADDRESS
&& IS_KERNEL_ADDRESS(address))
return B_BAD_VALUE;
@@ -6416,10 +6469,12 @@
size, lock, protection, 0, 0, &virtualRestrictions,
&physicalRestrictions, false, &address);
- if (area >= B_OK
- && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
- delete_area(area);
- return B_BAD_ADDRESS;
+ if (area >= B_OK) {
+ status = copy_ref_var_to_user(address, userAddress);
+ if (status < B_OK) {
+ delete_area(area);
+ return status;
+ }
}
return area;
@@ -6453,11 +6508,14 @@
fix_protection(&protection);
- if (!IS_USER_ADDRESS(userName) || !IS_USER_ADDRESS(userAddress)
- || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK
- || user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
+ if (!IS_USER_ADDRESS(userName)
+ || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userAddress, address);
+ if (status != B_OK)
+ return status;
+
if (addressSpec == B_EXACT_ADDRESS) {
if ((addr_t)address + size < (addr_t)address
|| (addr_t)address % B_PAGE_SIZE != 0) {
@@ -6475,8 +6533,11 @@
if (area < B_OK)
return area;
- if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK)
- return B_BAD_ADDRESS;
+ status = copy_ref_var_to_user(address, userAddress);
+ if (status < B_OK) {
+ delete_area(area);
+ return status;
+ }
return area;
}
--
To view, visit https://review.haiku-os.org/c/haiku/+/2874
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I3fc15613d4443b50980291d8f9300dc550ed95b0
Gerrit-Change-Number: 2874
Gerrit-PatchSet: 1
Gerrit-Owner: X512 <danger_mail@xxxxxxx>
Gerrit-Reviewer: Please take over this change <jerome.duval@xxxxxxxxx>
Gerrit-MessageType: newchange