about summary refs log tree commit diff stats
path: root/src/libtools
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-10-21 11:32:35 +0200
committerptitSeb <sebastien.chev@gmail.com>2023-10-21 11:32:35 +0200
commita83091bc3b9e84a9471aeadfef40b501b0399988 (patch)
tree6ed5b0fbacdf083eaaf8d7f1e40363337df04424 /src/libtools
parent7372540fce848b69432e3201a0cac0c453f2eae8 (diff)
downloadbox64-a83091bc3b9e84a9471aeadfef40b501b0399988.tar.gz
box64-a83091bc3b9e84a9471aeadfef40b501b0399988.zip
[ARM64_DYNAREC] More handling of SIGBUS on device memory (for Doomvk 2016 on NVidia)
Diffstat (limited to 'src/libtools')
-rw-r--r--src/libtools/signals.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index 3c88d345..3819f29c 100644
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -648,6 +648,96 @@ int sigbus_specialcases(siginfo_t* info, void * ucntx, void* pc, void* _fpsimd)
         p->uc_mcontext.pc+=4;   // go to next opcode
         return 1;
     }
+    if((opcode&0b00111111010000000000000000000000)==0b00111101010000000000000000000000) {
+        // this is VLDR
+        int scale = (opcode>>30)&3;
+        if((opcode>>23)&1)
+            scale+=4;
+        if(scale>4)
+            return 0;
+        if(!fpsimd)
+            return 0;
+        uint64_t offset = (opcode>>10)&0b111111111111;
+        offset<<=scale;
+        int val = opcode&31;
+        int dest = (opcode>>5)&31;
+        uint8_t* addr = (uint8_t*)(p->uc_mcontext.regs[dest] + offset);
+        __uint128_t value = 0;
+        if(scale>2 && ((uintptr_t)addr)&3==0) {
+            for(int i=0; i<(1<<(scale-2)); ++i)
+                value |= ((__uint128_t)(((uint32_t*)addr)[i]))<<(i*32);
+        } else
+            for(int i=0; i<(1<<scale); ++i)
+                value |= ((__uint128_t)addr[i])<<(i*8);
+        fpsimd->vregs[val] = value;
+        p->uc_mcontext.pc+=4;   // go to next opcode
+        return 1;
+    }
+    if((opcode&0b00111111011000000000110000000000)==0b00111100010000000000000000000000) {
+        // this is VLDRU
+        int scale = (opcode>>30)&3;
+        if((opcode>>23)&1)
+            scale+=4;
+        if(scale>4)
+            return 0;
+        if(!fpsimd)
+            return 0;
+        int64_t offset = (opcode>>12)&0b111111111;
+        if((offset>>(9-1))&1)
+            offset |= (0xffffffffffffffffll<<9);
+        int val = opcode&31;
+        int dest = (opcode>>5)&31;
+        uint8_t* addr = (uint8_t*)(p->uc_mcontext.regs[dest] + offset);
+        __uint128_t value = 0;
+        if(scale>2 && ((uintptr_t)addr)&3==0) {
+            for(int i=0; i<(1<<(scale-2)); ++i)
+                value |= ((__uint128_t)(((uint32_t*)addr)[i]))<<(i*32);
+        } else
+            for(int i=0; i<(1<<scale); ++i)
+                value |= ((__uint128_t)addr[i])<<(i*8);
+        fpsimd->vregs[val] = value;
+        p->uc_mcontext.pc+=4;   // go to next opcode
+        return 1;
+    }
+    if((opcode&0b10111111110000000000000000000000)==0b10111001010000000000000000000000) {
+        // this is LDR
+        int scale = (opcode>>30)&3;
+        int val = opcode&31;
+        int dest = (opcode>>5)&31;
+        uint64_t offset = (opcode>>10)&0b111111111111;
+        offset<<=scale;
+        uint8_t* addr = (uint8_t*)(p->uc_mcontext.regs[dest] + offset);
+        uint64_t value = 0;
+        if(scale==3 && ((uintptr_t)addr)&3==0) {
+            for(int i=0; i<2; ++i)
+                value |= ((uint64_t)((uint32_t*)addr)[i]) << (i*32);
+        } else
+            for(int i=0; i<(1<<scale); ++i)
+                value |= ((uint64_t)addr[i]) << (i*8);
+        p->uc_mcontext.regs[val] = value;
+        p->uc_mcontext.pc+=4;   // go to next opcode
+        return 1;
+    }
+    if((opcode&0b10111111111000000000110000000000) == 0b10111000010000000000000000000000) {
+        // this is a LDUR
+        int size = 1<<((opcode>>30)&3);
+        int val = opcode&31;
+        int dest = (opcode>>5)&31;
+        int64_t offset = (opcode>>12)&0b111111111;
+        if((offset>>(9-1))&1)
+            offset |= (0xffffffffffffffffll<<9);
+        uint8_t* addr = (uint8_t*)(p->uc_mcontext.regs[dest] + offset);
+        uint64_t value = 0;
+        if(size==8 && ((uintptr_t)addr)&3==0) {
+            for(int i=0; i<2; ++i)
+                value |= ((uint64_t)((uint32_t*)addr)[i]) << (i*32);
+        } else
+            for(int i=0; i<size; ++i)
+                value |= ((uint64_t)addr[i]) << (i*8);
+        p->uc_mcontext.regs[val] = value;
+        p->uc_mcontext.pc+=4;   // go to next opcode
+        return 1;
+    }
 #endif
     return 0;
 }