[haiku-commits] Change in haiku[master]: kernel/x86_64: IA32 compatibility mode.

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 3 Jun 2020 11:04:16 +0000

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(&currentThread->flags, THREAD_FLAGS_COMPAT_MODE);
+       else
+               atomic_and(&currentThread->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

Other related posts:

  • » [haiku-commits] Change in haiku[master]: kernel/x86_64: IA32 compatibility mode. - Gerrit