about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-06-17 11:32:56 +0200
committerptitSeb <sebastien.chev@gmail.com>2023-06-17 11:32:56 +0200
commitbf9e5b8e6e3b42768a787f1a3d3c1f423d1fb38f (patch)
tree77430b88dda5a324dcf00055c0ffe90cbef6bdb8 /src
parent7e282c9027a3c7e563b4492a0004174b42de0819 (diff)
downloadbox64-bf9e5b8e6e3b42768a787f1a3d3c1f423d1fb38f.tar.gz
box64-bf9e5b8e6e3b42768a787f1a3d3c1f423d1fb38f.zip
Added support for creating 32bits selector (no 32bits execution yet)
Diffstat (limited to 'src')
-rwxr-xr-xsrc/box64context.c16
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_00.c16
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_helper.c5
-rwxr-xr-xsrc/dynarec/dynarec.c6
-rwxr-xr-xsrc/emu/x64emu.c6
-rwxr-xr-xsrc/emu/x64run.c24
-rwxr-xr-xsrc/emu/x64run_private.h1
-rwxr-xr-xsrc/emu/x64syscall.c2
-rwxr-xr-xsrc/emu/x64tls.c178
-rwxr-xr-xsrc/emu/x86syscall.c284
-rwxr-xr-xsrc/include/box64context.h6
-rwxr-xr-xsrc/include/x64tls.h2
-rwxr-xr-xsrc/libtools/signals.c7
-rwxr-xr-xsrc/main.c2
14 files changed, 482 insertions, 73 deletions
diff --git a/src/box64context.c b/src/box64context.c
index fc626305..ff65391c 100755
--- a/src/box64context.c
+++ b/src/box64context.c
@@ -243,6 +243,22 @@ box64context_t *NewBox64Context(int argc)
     context->canary[getrand(4)] = 0;
     printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at FS:0x28, value:%08X\n", *(uint32_t*)context->canary);
 
+    // init segments
+    for(int i=0; i<16; i++) {
+        context->segtls[i].limit = (uintptr_t)-1LL;
+    }
+    context->segtls[10].key_init = 0;    // 0x53 selector
+    context->segtls[10].present = 1;
+    context->segtls[8].key_init = 0;    // 0x43 selector
+    context->segtls[8].present = 1;
+    context->segtls[6].key_init = 0;    // 0x33 selector
+    context->segtls[6].present = 1;
+    context->segtls[5].key_init = 0;    // 0x2b selector
+    context->segtls[5].present = 1;
+    context->segtls[4].key_init = 0;    // 0x23 selector
+    context->segtls[4].present = 1;
+    context->segtls[4].is32bits = 1;
+
     initAllHelpers(context);
 
     return context;
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index e33b2b01..2d621ef6 100755
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -1816,6 +1816,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             if(box64_wine && u8==0x2D) {
                 // lets do nothing
                 MESSAGE(LOG_INFO, "INT 2D Windows anti-debug hack\n");
+            } else if (u8==0x80) {
+                INST_NAME("32bits SYSCALL");
+                NOTEST(x1);
+                SMEND();
+                GETIP(addr);
+                STORE_XEMU_CALL(xRIP);
+                CALL_S(x86Syscall, -1);
+                LOAD_XEMU_CALL(xRIP);
+                TABLE64(x3, addr); // expected return address
+                CMPSx_REG(xRIP, x3);
+                B_MARK(cNE);
+                LDRw_U12(w1, xEmu, offsetof(x64emu_t, quit));
+                CBZw_NEXT(w1);
+                MARK;
+                LOAD_XEMU_REM();
+                jump_to_epilog(dyn, 0, xRIP, ninst);
             } else {
                 SETFLAGS(X_ALL, SF_SET);    // Hack to set flags in "don't care" state
                 GETIP(ip);
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index 29442c1f..e141655a 100755
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -545,9 +545,8 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
     // POP CS
     POP1(x2);
     STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
-    MOVZw(x1, 0);
-    STRx_U12(x1, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
-    STRx_U12(x1, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
+    STRx_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
+    STRx_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
     // POP EFLAGS
     POP1(xFlags);
     MOV32w(x1, 0x3F7FD7);
diff --git a/src/dynarec/dynarec.c b/src/dynarec/dynarec.c
index 05d5b5ad..e430fa04 100755
--- a/src/dynarec/dynarec.c
+++ b/src/dynarec/dynarec.c
@@ -121,7 +121,8 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
         R_RIP = addr;
         emu->df = d_none;
         while(!emu->quit) {
-            dynablock_t* block = (skip)?NULL:DBGetBlock(emu, R_RIP, 1);
+            int is32bits = (emu->segs[_CS]==0x23);
+            dynablock_t* block = (skip || is32bits)?NULL:DBGetBlock(emu, R_RIP, 1);
             if(!block || !block->block || !block->done) {
                 skip = 0;
                 // no block, of block doesn't have DynaRec content (yet, temp is not null)
@@ -208,7 +209,8 @@ int DynaRun(x64emu_t* emu)
 #ifdef DYNAREC
     else {
         while(!emu->quit) {
-            dynablock_t* block = (skip)?NULL:DBGetBlock(emu, R_RIP, 1);
+            int is32bits = (emu->segs[_CS]==0x23);
+            dynablock_t* block = (skip || is32bits)?NULL:DBGetBlock(emu, R_RIP, 1);
             if(!block || !block->block || !block->done) {
                 skip = 0;
                 // no block, of block doesn't have DynaRec content (yet, temp is not null)
diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c
index 620bea97..05ec337f 100755
--- a/src/emu/x64emu.c
+++ b/src/emu/x64emu.c
@@ -75,9 +75,9 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
     R_RIP = start;
     R_RSP = (stack + stacksize) & ~7;   // align stack start, always
     // fake init of segments...
-    emu->segs[_CS] = 0x73;
-    emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x7b;
-    emu->segs[_FS] = 0x33;
+    emu->segs[_CS] = 0x33;
+    emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x2b;
+    emu->segs[_FS] = 0x43;
     emu->segs[_GS] = default_gs;
     // setup fpu regs
     reset_fpu(emu);
diff --git a/src/emu/x64run.c b/src/emu/x64run.c
index c6523ed7..016e4922 100755
--- a/src/emu/x64run.c
+++ b/src/emu/x64run.c
@@ -52,6 +52,12 @@ int Run(x64emu_t *emu, int step)
     rex_t rex;
     int rep;    // 0 none, 1=F2 prefix, 2=F3 prefix
     int unimp = 0;
+    int is32bits = (emu->segs[_CS]==0x23);
+    if(is32bits) {
+        printf_log(LOG_INFO, "Error, 32bits execution not yet supported\n");
+        emu->quit = 1;
+        return 0;
+    }
 
     if(emu->quit)
         return 0;
@@ -62,7 +68,7 @@ int Run(x64emu_t *emu, int step)
         return 0;
     }
     //ref opcode: http://ref.x64asm.net/geek32.html#xA1
-    printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)addr, (void*)R_RSP);
+    printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p is32bits=%D\n", emu, (void*)addr, (void*)R_RSP, is32bits);
 
 x64emurun:
 #ifndef TEST_INTERPRETER
@@ -89,10 +95,11 @@ x64emurun:
         while((opcode==0x3E) || (opcode==0x26))   //Branch Taken Hint ignored
             opcode = F8;
         rex.rex = 0;
-        while(opcode>=0x40 && opcode<=0x4f) {
-            rex.rex = opcode;
-            opcode = F8;
-        }
+        if(!is32bits)
+            while(opcode>=0x40 && opcode<=0x4f) {
+                rex.rex = opcode;
+                opcode = F8;
+            }
 
         switch(opcode) {
 
@@ -1158,6 +1165,12 @@ x64emurun:
             if(box64_wine && tmp8u==0x2D) {
                 // lets ignore the INT 2D
                 printf_log(LOG_DEBUG, "INT 2D called\n");
+            } else if (tmp8u==0x80) {
+                // 32bits syscall
+                #ifndef TEST_INTERPRETER
+                x86Syscall(emu);
+                STEP;
+                #endif
             } else {
                 #ifndef TEST_INTERPRETER
                 emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
@@ -1681,6 +1694,7 @@ x64emurun:
 
 
 fini:
+if(emu->segs[_CS]!=0x33) printf_log(LOG_NONE, "Warning, CS is not default value: 0x%x\n", emu->segs[_CS]);
 #ifndef TEST_INTERPRETER
     printf_log(LOG_DEBUG, "End of X86 run (%p), RIP=%p, Stack=%p, unimp=%d, emu->fork=%d, emu->uc_link=%p, emu->quit=%d\n", emu, (void*)R_RIP, (void*)R_RSP, unimp, emu->fork, emu->uc_link, emu->quit);
     if(unimp) {
diff --git a/src/emu/x64run_private.h b/src/emu/x64run_private.h
index 23750022..37947164 100755
--- a/src/emu/x64run_private.h
+++ b/src/emu/x64run_private.h
@@ -147,6 +147,7 @@ uintptr_t TestF30F(x64test_t *test, rex_t rex, uintptr_t addr);
 void x64Syscall(x64emu_t *emu);
 void x64Int3(x64emu_t* emu, uintptr_t* addr);
 x64emu_t* x64emu_fork(x64emu_t* e, int forktype);
+void x86Syscall(x64emu_t *emu); //32bits syscall
 
 uintptr_t GetSegmentBaseEmu(x64emu_t* emu, int seg);
 #define GetGSBaseEmu(emu)    GetSegmentBaseEmu(emu, _GS)
diff --git a/src/emu/x64syscall.c b/src/emu/x64syscall.c
index 242184b3..4f9d6c88 100755
--- a/src/emu/x64syscall.c
+++ b/src/emu/x64syscall.c
@@ -77,7 +77,7 @@ typedef struct scwrap_s {
     int nbpars;
 } scwrap_t;
 
-scwrap_t syscallwrap[] = {
+static scwrap_t syscallwrap[] = {
     //{ 0, __NR_read, 3 },      // wrapped so SA_RESTART can be handled by libc
     //{ 1, __NR_write, 3 },     // same
     //{ 2, __NR_open, 3 },      // flags need transformation
diff --git a/src/emu/x64tls.c b/src/emu/x64tls.c
index 4673b4a3..af7c4aa0 100755
--- a/src/emu/x64tls.c
+++ b/src/emu/x64tls.c
@@ -15,7 +15,7 @@
 typedef struct thread_area_s
 {
              int  entry_number;
-        uintptr_t base_addr;
+       uintptr_t  base_addr;
     unsigned int  limit;
     unsigned int  seg_32bit:1;
     unsigned int  contents:2;
@@ -24,28 +24,77 @@ typedef struct thread_area_s
     unsigned int  seg_not_present:1;
     unsigned int  useable:1;
 } thread_area_t;
+typedef struct thread_area_32_s
+{
+             int  entry_number;
+        uint32_t  base_addr;
+    unsigned int  limit;
+    unsigned int  seg_32bit:1;
+    unsigned int  contents:2;
+    unsigned int  read_exec_only:1;
+    unsigned int  limit_in_pages:1;
+    unsigned int  seg_not_present:1;
+    unsigned int  useable:1;
+} thread_area_32_t;
 
-static pthread_once_t thread_key_once0 = PTHREAD_ONCE_INIT;
-static pthread_once_t thread_key_once1 = PTHREAD_ONCE_INIT;
-static pthread_once_t thread_key_once2 = PTHREAD_ONCE_INIT;
-static pthread_once_t thread_key_once3 = PTHREAD_ONCE_INIT;
+uint32_t my_set_thread_area(thread_area_t* td)
+{
+    printf_log(/*LOG_DEBUG*/LOG_NONE, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only);
 
-static void thread_key_alloc0() {
-	pthread_key_create(&my_context->segtls[0].key, NULL);
-}
-static void thread_key_alloc1() {
-	pthread_key_create(&my_context->segtls[1].key, NULL);
-}
-static void thread_key_alloc2() {
-	pthread_key_create(&my_context->segtls[2].key, NULL);
-}
-static void thread_key_alloc3() {
-	pthread_key_create(&my_context->segtls[3].key, NULL);
+    int isempty = 0;
+    // first, check if the "user_desc", here td, is "empty"
+    if(td->read_exec_only==1 && td->seg_not_present==1)
+        if( !td->base_addr 
+         && !td->limit
+         && !td->seg_32bit 
+         && !td->contents 
+         && !td->limit_in_pages 
+         && !td->useable)
+            isempty = 1;
+    int idx = td->entry_number;
+    if(idx==-1) {
+        // find a free one
+        for (int i=9; i<15 && idx==-1; ++i)
+            if(!my_context->segtls[i].present)
+                idx=i;
+        if(idx==-1) {
+            errno = ESRCH;
+            return (uint32_t)-1;
+        }
+        td->entry_number = idx;
+    }
+    if(isempty && (td->entry_number<9 || td->entry_number>15)) {
+        errno = EINVAL;
+        return (uint32_t)-1;
+    }
+    if(isempty) {
+        memset(&my_context->segtls[td->entry_number], 0, sizeof(base_segment_t));
+        return 0;
+    }
+    if((idx<9 || idx>15)) {
+        errno = EINVAL;
+        return (uint32_t)-1;
+    }
+
+    my_context->segtls[idx].base = td->base_addr;
+    my_context->segtls[idx].limit = td->limit;
+    my_context->segtls[idx].present = 1;
+    my_context->segtls[idx].is32bits = 0;
+    if(!my_context->segtls[idx].key_init) {
+        pthread_key_create(&my_context->segtls[idx].key, NULL);
+        my_context->segtls[idx].key_init = 1;
+    }
+
+    pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base);
+
+    ResetSegmentsCache(thread_get_emu());
+
+    return 0;
 }
 
-uint32_t my_set_thread_area(thread_area_t* td)
+uint32_t my_set_thread_area_32(thread_area_32_t* td)
 {
-    printf_log(LOG_DEBUG, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only);
+    printf_log(LOG_DEBUG, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)(uintptr_t)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only);
 
     int isempty = 0;
     // first, check if the "user_desc", here td, is "empty"
@@ -60,39 +109,38 @@ uint32_t my_set_thread_area(thread_area_t* td)
     int idx = td->entry_number;
     if(idx==-1) {
         // find a free one
-        for (int i=0; i<3 && idx==-1; ++i)
+        for (int i=9; i<15 && idx==-1; ++i)
             if(!my_context->segtls[i].present)
                 idx=i;
         if(idx==-1) {
             errno = ESRCH;
             return (uint32_t)-1;
         }
-        idx+=7;
         td->entry_number = idx;
     }
-    if(isempty && (td->entry_number<7 || td->entry_number>7+2)) {
+    if(isempty && (td->entry_number<9 || td->entry_number>15)) {
         errno = EINVAL;
         return (uint32_t)-1;
     }
     if(isempty) {
-        memset(&my_context->segtls[td->entry_number-7], 0, sizeof(base_segment_t));
+        memset(&my_context->segtls[td->entry_number], 0, sizeof(base_segment_t));
         return 0;
     }
-    if((idx<7 || idx>7+2)) {
+    if((idx<9 || idx>15)) {
         errno = EINVAL;
         return (uint32_t)-1;
     }
 
-    my_context->segtls[idx-7].base = td->base_addr;
-    my_context->segtls[idx-7].limit = td->limit;
-    my_context->segtls[idx-7].present = 1;
-    switch (idx-7) {
-        case 0:	pthread_once(&thread_key_once0, thread_key_alloc0); break;
-        case 1:	pthread_once(&thread_key_once1, thread_key_alloc1); break;
-        case 2:	pthread_once(&thread_key_once2, thread_key_alloc2); break;
+    my_context->segtls[idx].base = td->base_addr;
+    my_context->segtls[idx].limit = td->limit;
+    my_context->segtls[idx].present = 1;
+    my_context->segtls[idx].is32bits = 1;
+    if(!my_context->segtls[idx].key_init) {
+        pthread_key_create(&my_context->segtls[idx].key, NULL);
+        my_context->segtls[idx].key_init = 1;
     }
 
-    pthread_setspecific(my_context->segtls[idx-7].key, (void*)my_context->segtls[idx-7].base);
+    pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base);
 
     ResetSegmentsCache(thread_get_emu());
 
@@ -116,8 +164,8 @@ uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size)
         return (uint32_t)-1;
     }
 
-    int idx = td->entry_number - 7;
-    if(idx<0 || idx>2) {
+    int idx = td->entry_number;
+    if(idx<9 || idx>15) {
         errno = EINVAL;
         return (uint32_t)-1;
     }
@@ -133,35 +181,52 @@ uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size)
     return 0;
 }
 
+int GetTID();
 int my_arch_prctl(x64emu_t *emu, int code, void* addr)
 {
-    //printf_log(LOG_INFO, "%04d| arch_prctl(0x%x, %p) (RSP=%p)\n", GetTID(), code, addr,(void*)R_RSP);
+    printf_log(LOG_DEBUG, "%04d| arch_prctl(0x%x, %p) (RSP=%p, FS=0x%x, GS=0x%x)\n", GetTID(), code, addr,(void*)R_RSP, emu->segs[_FS], emu->segs[_GS]);
 
     #define ARCH_SET_GS          0x1001
     #define ARCH_SET_FS          0x1002
     #define ARCH_GET_FS          0x1003
     #define ARCH_GET_GS          0x1004
+    int seg = 0;
+    int idx = 0;
     switch(code) {
         case ARCH_GET_GS:
             *(void**)addr = GetSegmentBase(emu->segs[_GS]);
             return 0;
-        case ARCH_SET_GS:
-            pthread_once(&thread_key_once3, thread_key_alloc3);
-            if(emu->segs[_GS]!=(0xa<<3))
-                emu->segs[_GS] = 0xa<<3;    // should not move!
-            emu->segs_serial[_GS] = 0;
-            my_context->segtls[3].base = (uintptr_t)addr;
-            my_context->segtls[3].limit = 0;
-            my_context->segtls[3].present = 1;
-            pthread_setspecific(my_context->segtls[3].key, (void*)my_context->segtls[3].base);
-            ResetSegmentsCache(emu);
-            return 0;
         case ARCH_GET_FS:
             *(void**)addr = GetSegmentBase(emu->segs[_FS]);
             return 0;
+        case ARCH_SET_FS:
+        case ARCH_SET_GS:
+            seg=(code==ARCH_SET_FS)?_FS:_GS;
+            if(emu->segs[seg]==0) {
+                errno = EINVAL;
+                return -1;
+            }
+            idx = emu->segs[seg] >> 3;
+            if(idx<0 || idx>15) {
+                errno = EINVAL;
+                return -1;
+            }
+            emu->segs_serial[seg] = 0;
+            my_context->segtls[idx].base = (uintptr_t)addr;
+            my_context->segtls[idx].limit = 0;
+            my_context->segtls[idx].present = 1;
+            if(idx>8 && !my_context->segtls[idx].key_init) {
+                pthread_key_create(&my_context->segtls[idx].key, NULL);
+                my_context->segtls[idx].key_init = 1;
+            }
+            if(my_context->segtls[idx].key_init)
+                pthread_setspecific(my_context->segtls[idx].key, addr);
+            ResetSegmentsCache(emu);
+            return 0;
     }
     // other are unsupported
     printf_log(LOG_INFO, "warning, call to unsupported arch_prctl(0x%x, %p)\n", code, addr);
+    errno = ENOSYS;
     return -1;
 }
 
@@ -286,7 +351,7 @@ tlsdatasize_t* getTLSData(box64context_t *context)
     return ptr;
 }
 
-static void* GetSeg33Base()
+static void* GetSeg43Base()
 {
     tlsdatasize_t* ptr = getTLSData(my_context);
     return ptr->data;
@@ -299,16 +364,17 @@ void* GetSegmentBase(uint32_t desc)
         return NULL;
     }
     int base = desc>>3;
-    if(base==0xe || base==0xf)
-        return NULL;    // regular value...
-    if(base==0x6)
-        return GetSeg33Base();
-
-    if(base>6 && base<11 && my_context->segtls[base-7].present) {
-        void* ptr = pthread_getspecific(my_context->segtls[base-7].key);
+    if(base==0x8 && !my_context->segtls[base].key_init)
+        return GetSeg43Base();
+    if(base>15) {
+        printf_log(LOG_NONE, "Warning, accessing segment unknown 0x%x or unset\n", desc);
+        return NULL;
+    }
+    if(my_context->segtls[base].key_init) {
+        void* ptr = pthread_getspecific(my_context->segtls[base].key);
         return ptr;
     }
-
-    printf_log(LOG_NONE, "Warning, accessing segment unknown 0x%x or unset\n", desc);
-    return NULL;
+    
+    void* ptr = (void*)my_context->segtls[base].base;
+    return ptr;
 }
diff --git a/src/emu/x86syscall.c b/src/emu/x86syscall.c
new file mode 100755
index 00000000..c1f7bce2
--- /dev/null
+++ b/src/emu/x86syscall.c
@@ -0,0 +1,284 @@
+#define _GNU_SOURCE         /* See feature_test_macros(7) */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/syscall.h>   /* For SYS_xxx definitions */
+#include <unistd.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <asm/stat.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#ifndef __NR_socketcall
+#include <linux/net.h>
+#include <sys/socket.h>
+#endif
+#include <sys/resource.h>
+#include <poll.h>
+
+#include "debug.h"
+#include "box64stack.h"
+#include "x64emu.h"
+#include "x64run.h"
+#include "x64emu_private.h"
+#include "x64trace.h"
+#include "myalign.h"
+#include "box64context.h"
+#include "callback.h"
+#include "signals.h"
+#include "x64tls.h"
+
+
+// Syscall table for x86_64 can be found 
+typedef struct scwrap_s {
+    uint32_t x86s;
+    int nats;
+    int nbpars;
+} scwrap_t;
+
+static scwrap_t syscallwrap[] = {
+    //{ 2, __NR_fork, 1 },  
+    //{ 3, __NR_read, 3 },  // wrapped so SA_RESTART can be handled by libc
+    //{ 4, __NR_write, 3 }, // same
+    //{ 5, __NR_open, 3 },  // flags need transformation
+    //{ 6, __NR_close, 1 },   // wrapped so SA_RESTART can be handled by libc
+    //{ 7, __NR_waitpid, 3 },
+    //{ 10, __NR_unlink, 1 },
+    //{ 12, __NR_chdir, 1 },
+    //{ 13, __NR_time, 1 },
+    //{ 15, __NR_chmod, 2 },
+    //{ 19, __NR_lseek, 3 },
+    //{ 20, __NR_getpid, 0 },
+    //{ 24, __NR_getuid, 0 },
+    //{ 33, __NR_access, 2 },
+    //{ 37, __NR_kill, 2 },
+    //{ 38, __NR_rename, 2 },
+    //{ 39, __NR_mkdir, 2 },
+    //{ 40, __NR_rmdir, 1 },
+    //{ 41, __NR_dup, 1 },
+    //{ 42, __NR_pipe, 1 },
+    //{ 45, __NR_brk, 1 },
+    //{ 47, __NR_getgid, 0 },
+    //{ 49, __NR_geteuid, 0 },
+    //{ 50, __NR_getegid, 0 },
+    //{ 54, __NR_ioctl, 3 },    // should be wrapped to allow SA_RESTART handling by libc, but syscall is only 3 arguments, ioctl can be 5
+    //{ 55, __NR_fcntl, 3 },    // wrapped to allow filter of F_SETFD
+    //{ 60, __NR_umask, 1 },
+    //{ 63, __NR_dup2, 2 },
+    //{ 64, __NR_getppid, 0 },
+    //{ 66, __NR_setsid, 0 },
+    //{ 75, __NR_setrlimit, 2 },
+    //{ 76, __NR_getrlimit, 2 },
+    //{ 77, __NR_getrusage, 2 },
+    //{ 78, __NR_gettimeofday, 2 },
+    //{ 83, __NR_symlink, 2 },
+    //{ 82, __NR_select, 5 },
+    //{ 85, __NR_readlink, 3 },
+    //{ 91, __NR_munmap, 2 },
+    //{ 94, __NR_fchmod, 2 },
+    //{ 99, __NR_statfs, 2 },
+    //{ 102, __NR_socketcall, 2 },
+    //{ 104, __NR_setitimer, 3 },
+    //{ 105, __NR_getitimer, 2 },
+    //{ 106, __NR_newstat, 2 },
+    //{ 106, __NR_stat, 2 },
+    //{ 107, __NR_newlstat, 2 },
+    //{ 107, __NR_lstat, 2 },
+    //{ 108, __NR_newfstat, 2 },
+    //{ 108, __NR_fstat, 2 },
+    //{ 109, __NR_olduname, 1 },
+    //{ 110, __NR_iopl, 1 },
+    //{ 114, __NR_wait4, 4 }, //TODO: check struct rusage alignment
+    //{ 117, __NR_ipc, 6 },
+    //{ 119, __NR_sigreturn, 0},
+    //{ 120, __NR_clone, 5 },    // need works
+    //{ 122, __NR_uname, 1 },
+    //{ 123, __NR_modify_ldt },
+    //{ 125, __NR_mprotect, 3 },
+    //{ 136, __NR_personality, 1 },
+    //{ 140, __NR__llseek, 5 },
+    //{ 141, __NR_getdents, 3 },
+    //{ 142, __NR__newselect, 5 },
+    //{ 143, __NR_flock,  2 },
+    //{ 144, __NR_msync, 3 },
+    //{ 145, __NR_readv, 3 },
+    //{ 146, __NR_writev, 3 },
+    //{ 148, __NR_fdatasync, 1 },
+    //{ 149, __NR__sysctl, 1 },    // need wrapping?
+    //{ 156, __NR_sched_setscheduler, 3 },
+    //{ 157, __NR_sched_getscheduler, 1 },
+    //{ 158, __NR_sched_yield, 0 },
+    //{ 162, __NR_nanosleep, 2 },
+    //{ 164, __NR_setresuid, 3 },
+    //{ 168, __NR_poll, 3 },    // wrapped to allow SA_RESTART wrapping by libc
+    //{ 172, __NR_prctl, 5 },
+    //{ 173, __NR_rt_sigreturn, 0 },
+    //{ 175, __NR_rt_sigprocmask, 4 },
+    //{ 179, __NR_rt_sigsuspend, 2 },
+    //{ 183, __NR_getcwd, 2 },
+    //{ 184, __NR_capget, 2},
+    //{ 185, __NR_capset, 2},
+    //{ 186, __NR_sigaltstack, 2 },    // neeed wrap or something?
+    //{ 191, __NR_ugetrlimit, 2 },
+//    { 192, __NR_mmap2, 6},
+    //{ 195, __NR_stat64, 2 },  // need proprer wrap because of structure size change
+    //{ 196, __NR_lstat64, 2 }, // need proprer wrap because of structure size change
+    //{ 197, __NR_fstat64, 2 },  // need proprer wrap because of structure size change
+    //{ 199, __NR_getuid32, 0 },
+    //{ 200, __NR_getgid32, 0 },
+    //{ 201, __NR_geteuid32, 0 },
+    //{ 202, __NR_getegid32, 0 },
+    //{ 208, __NR_setresuid32, 3 },
+    //{ 209, __NR_getresuid32, 3 },
+    //{ 210, __NR_setresgid32, 3 },
+    //{ 211, __NR_getresgid32, 3 },
+    //{ 220, __NR_getdents64, 3 },
+    //{ 221, __NR_fcntl64, 3 },
+    { 224, __NR_gettid, 0 },
+    //{ 240, __NR_futex, 6 },
+    //{ 241, __NR_sched_setaffinity, 3 },
+    //{ 242, __NR_sched_getaffinity, 3 },
+    //{ 252, __NR_exit_group, 1 },
+    //{ 254, __NR_epoll_create, 1 },
+    //{ 255, __NR_epoll_ctl, 4 },
+    //{ 256, __NR_epoll_wait, 4 },
+    //{ 265, __NR_clock_gettime, 2 },
+    //{ 266, __NR_clock_getres, 2 },
+    //{ 270, __NR_tgkill, 3 },
+    //{ 271, __NR_utimes, 2 },
+    //{ 291, __NR_inotify_init, 0},
+    //{ 292, __NR_inotify_add_watch, 3},
+    //{ 293, __NR_inotify_rm_watch, 2},
+    //{ 311, __NR_set_robust_list, 2 },
+    //{ 312, __NR_get_robust_list, 4 },
+    //{ 318, __NR_getcpu, 3},
+    //{ 328, __NR_eventfd2, 2},
+    //{ 329, __NR_epoll_create1, 1 },
+    //{ 331, __NR_pipe2, 2},
+    //{ 332, __NR_inotify_init1, 1},
+    //{ 355, __NR_getrandom, 3 },
+    //{ 356, __NR_memfd_create, 2},
+    //{ 449, __NR_futex_waitv, 5},
+};
+
+struct mmap_arg_struct {
+    unsigned long addr;
+    unsigned long len;
+    unsigned long prot;
+    unsigned long flags;
+    unsigned long fd;
+    unsigned long offset;
+};
+
+#undef st_atime
+#undef st_ctime
+#undef st_mtime
+
+struct x64_pt_regs {
+	long ebx;
+	long ecx;
+	long edx;
+	long esi;
+	long edi;
+	long ebp;
+	long eax;
+	int  xds;
+	int  xes;
+	int  xfs;
+	int  xgs;
+	long orig_eax;
+	long eip;
+	int  xcs;
+	long eflags;
+	long esp;
+	int  xss;
+};
+
+#ifndef __NR_olduname
+struct oldold_utsname {
+        char sysname[9];
+        char nodename[9];
+        char release[9];
+        char version[9];
+        char machine[9];
+};
+#endif
+struct old_utsname {
+        char sysname[65];
+        char nodename[65];
+        char release[65];
+        char version[65];
+        char machine[65];
+};
+
+struct i386_user_desc {
+    unsigned int  entry_number;
+    unsigned long base_addr;
+    unsigned int  limit;
+    unsigned int  seg_32bit:1;
+    unsigned int  contents:2;
+    unsigned int  read_exec_only:1;
+    unsigned int  limit_in_pages:1;
+    unsigned int  seg_not_present:1;
+    unsigned int  useable:1;
+};
+
+void EXPORT x86Syscall(x64emu_t *emu)
+{
+    uint32_t s = R_EAX;
+    printf_log(LOG_DEBUG, "%p: Calling 32bits syscall 0x%02X (%d) %p %p %p %p %p", (void*)R_RIP, s, s, (void*)(uintptr_t)R_EBX, (void*)(uintptr_t)R_ECX, (void*)(uintptr_t)R_EDX, (void*)(uintptr_t)R_ESI, (void*)(uintptr_t)R_EDI); 
+    // check wrapper first
+    int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
+    for (int i=0; i<cnt; i++) {
+        if(syscallwrap[i].x86s == s) {
+            int sc = syscallwrap[i].nats;
+            switch(syscallwrap[i].nbpars) {
+                case 0: *(int32_t*)&R_EAX = syscall(sc); break;
+                case 1: *(int32_t*)&R_EAX = syscall(sc, R_EBX); break;
+                case 2: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX); break;
+                case 3: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX); break;
+                case 4: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI); break;
+                case 5: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI); break;
+                case 6: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP); break;
+                default:
+                   printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); 
+                   emu->quit = 1;
+                   return;
+            }
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
+            return;
+        }
+    }
+    switch (s) {
+        case 1: // sys_exit
+            emu->quit = 1;
+            emu->exit = 1;
+            //R_EAX = syscall(__NR_exit, R_EBX);  // the syscall should exit only current thread
+            R_EAX = R_EBX; // faking the syscall here, we don't want to really terminate the thread now
+            break;
+        /*case 123:   // SYS_modify_ldt
+            R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)(uintptr_t)R_ECX, R_EDX);
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            break;*/
+        case 243: // set_thread_area
+            R_EAX = my_set_thread_area_32((thread_area_32_t*)(uintptr_t)R_EBX);
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            break;
+        default:
+            printf_log(LOG_INFO, "Warning: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
+            R_EAX = (uint32_t)-ENOSYS;
+            return;
+    }
+    printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
+}
diff --git a/src/include/box64context.h b/src/include/box64context.h
index 9b38fa83..2f82e010 100755
--- a/src/include/box64context.h
+++ b/src/include/box64context.h
@@ -69,8 +69,10 @@ void add1lib_neededlib(needed_libs_t* needed, library_t* lib, const char* name);
 typedef struct base_segment_s {
     uintptr_t       base;
     uint64_t        limit;
-    int             present;
     pthread_key_t   key;
+    uint8_t         present;
+    uint8_t         is32bits;
+    uint8_t         key_init;
 } base_segment_t;
 
 typedef struct box64context_s {
@@ -174,7 +176,7 @@ typedef struct box64context_s {
     pthread_key_t       tlskey;     // then tls key to have actual tlsdata
     void*               tlsdata;    // the initial global tlsdata
     int64_t             tlssize;    // wanted size of tlsdata
-    base_segment_t      segtls[4];  // only handling 0/1/2 descriptors (3 is internal use)
+    base_segment_t      segtls[16];
 
     uintptr_t           *auxval_start;
 
diff --git a/src/include/x64tls.h b/src/include/x64tls.h
index 9ca97efb..b99e3bc0 100755
--- a/src/include/x64tls.h
+++ b/src/include/x64tls.h
@@ -2,8 +2,10 @@
 #define __X64_TLS_H__
 
 typedef struct thread_area_s thread_area_t;
+typedef struct thread_area_32_s thread_area_32_t;
 
 uint32_t my_set_thread_area(thread_area_t* td);
+uint32_t my_set_thread_area_32(thread_area_32_t* td);
 uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size);
 
 tlsdatasize_t* getTLSData(box64context_t *context);
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index 2bbe6bb2..76fd50eb 100755
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -1242,6 +1242,7 @@ exit(-1);
         }
         if(log_minimum<=box64_log) {
             static const char* reg_name[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", " R8", " R9","R10","R11", "R12","R13","R14","R15"};
+            static const char* seg_name[] = {"CS", "DS", "SS", "ES", "GS", "FS"};
             int shown_regs = 0;
 #ifdef DYNAREC
             uint32_t hash = 0;
@@ -1263,6 +1264,9 @@ exit(-1);
                     if(!(i%4)) printf_log(log_minimum, "\n");
                     printf_log(log_minimum, "%s:0x%016llx ", reg_name[i], p->uc_mcontext.regs[10+i]);
                 }
+                for (int i=0; i<3; ++i) {
+                    printf_log(log_minimum, "%s:0x%x ", seg_name[i], emu->segs[i]);
+                }
             }
             if(rsp!=addr && getProtection((uintptr_t)rsp-4*8) && getProtection((uintptr_t)rsp+4*8))
                 for (int i=-4; i<4; ++i) {
@@ -1275,6 +1279,9 @@ exit(-1);
                     if(!(i%4)) printf_log(log_minimum, "\n");
                     printf_log(log_minimum, "%s:0x%016llx ", reg_name[i], p->uc_mcontext.__gregs[16+i]);
                 }
+                for (int i=0; i<3; ++i) {
+                    printf_log(log_minimum, "%s:0x%x ", seg_name[i], emu->segs[i]);
+                }
             }
             if(rsp!=addr && getProtection((uintptr_t)rsp-4*8) && getProtection((uintptr_t)rsp+4*8))
                 for (int i=-4; i<4; ++i) {
diff --git a/src/main.c b/src/main.c
index b3983abd..9fb48f7d 100755
--- a/src/main.c
+++ b/src/main.c
@@ -121,7 +121,7 @@ int box64_isglibc234 = 0;
 char* box64_libGL = NULL;
 uintptr_t fmod_smc_start = 0;
 uintptr_t fmod_smc_end = 0;
-uint32_t default_gs = 0xa<<3;
+uint32_t default_gs = 0x53;
 int jit_gdb = 0;
 int box64_tcmalloc_minimal = 0;