From 977b7aeb5095eb4d77576c2e0b11d78b300d7870 Mon Sep 17 00:00:00 2001 From: Frode Solheim Date: Sat, 26 Sep 2015 01:23:14 +0200 Subject: [PATCH] JIT: Proper REX and and extended register support in access fault handler --- jit/exception_handler.cpp | 420 +++++++++++++++++++++++--------------- 1 file changed, 255 insertions(+), 165 deletions(-) diff --git a/jit/exception_handler.cpp b/jit/exception_handler.cpp index c3caa59c..8cf96f82 100644 --- a/jit/exception_handler.cpp +++ b/jit/exception_handler.cpp @@ -38,20 +38,28 @@ typedef LPEXCEPTION_POINTERS CONTEXT_T; #define CONTEXT_RBP(context) (context->ContextRecord->Rbp) #define CONTEXT_RSI(context) (context->ContextRecord->Rsi) #define CONTEXT_RDI(context) (context->ContextRecord->Rdi) +#define CONTEXT_R8(context) (context->ContextRecord->R8) +#define CONTEXT_R9(context) (context->ContextRecord->R9) +#define CONTEXT_R10(context) (context->ContextRecord->R10) +#define CONTEXT_R11(context) (context->ContextRecord->R11) +#define CONTEXT_R12(context) (context->ContextRecord->R12) +#define CONTEXT_R13(context) (context->ContextRecord->R13) +#define CONTEXT_R14(context) (context->ContextRecord->R14) +#define CONTEXT_R15(context) (context->ContextRecord->R15) #elif defined(_WIN32) && defined(CPU_i386) typedef LPEXCEPTION_POINTERS CONTEXT_T; #define HAVE_CONTEXT_T 1 -#define CONTEXT_EIP(context) (context->ContextRecord->Eip) -#define CONTEXT_EAX(context) (context->ContextRecord->Eax) -#define CONTEXT_ECX(context) (context->ContextRecord->Ecx) -#define CONTEXT_EDX(context) (context->ContextRecord->Edx) -#define CONTEXT_EBX(context) (context->ContextRecord->Ebx) -#define CONTEXT_ESP(context) (context->ContextRecord->Esp) -#define CONTEXT_EBP(context) (context->ContextRecord->Ebp) -#define CONTEXT_ESI(context) (context->ContextRecord->Esi) -#define CONTEXT_EDI(context) (context->ContextRecord->Edi) +#define CONTEXT_RIP(context) (context->ContextRecord->Eip) +#define CONTEXT_RAX(context) (context->ContextRecord->Eax) +#define CONTEXT_RCX(context) (context->ContextRecord->Ecx) +#define CONTEXT_RDX(context) (context->ContextRecord->Edx) +#define CONTEXT_RBX(context) (context->ContextRecord->Ebx) +#define CONTEXT_RSP(context) (context->ContextRecord->Esp) +#define CONTEXT_RBP(context) (context->ContextRecord->Ebp) +#define CONTEXT_RSI(context) (context->ContextRecord->Esi) +#define CONTEXT_RDI(context) (context->ContextRecord->Edi) #elif defined(HAVE_STRUCT_UCONTEXT_UC_MCONTEXT_GREGS) && defined(CPU_x86_64) @@ -66,20 +74,28 @@ typedef void *CONTEXT_T; #define CONTEXT_RBP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RBP]) #define CONTEXT_RSI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RSI]) #define CONTEXT_RDI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RDI]) +#define CONTEXT_R8(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R8]) +#define CONTEXT_R9(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R9]) +#define CONTEXT_R10(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R10]) +#define CONTEXT_R11(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R11]) +#define CONTEXT_R12(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R12]) +#define CONTEXT_R13(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R13]) +#define CONTEXT_R14(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R14]) +#define CONTEXT_R15(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_R15]) #elif defined(HAVE_STRUCT_UCONTEXT_UC_MCONTEXT_GREGS) && defined(CPU_i386) typedef void *CONTEXT_T; #define HAVE_CONTEXT_T 1 -#define CONTEXT_EIP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EIP]) -#define CONTEXT_EAX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EAX]) -#define CONTEXT_ECX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ECX]) -#define CONTEXT_EDX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EDX]) -#define CONTEXT_EBX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EBX]) -#define CONTEXT_ESP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ESP]) -#define CONTEXT_EBP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EBP]) -#define CONTEXT_ESI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ESI]) -#define CONTEXT_EDI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EDI]) +#define CONTEXT_RIP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EIP]) +#define CONTEXT_RAX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EAX]) +#define CONTEXT_RCX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ECX]) +#define CONTEXT_RDX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EDX]) +#define CONTEXT_RBX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EBX]) +#define CONTEXT_RSP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ESP]) +#define CONTEXT_RBP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EBP]) +#define CONTEXT_RSI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ESI]) +#define CONTEXT_RDI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EDI]) #elif defined(__DARWIN_UNIX03) && defined(CPU_x86_64) @@ -94,32 +110,32 @@ typedef void *CONTEXT_T; #define CONTEXT_RBP(context) (((ucontext_t *) context)->uc_mcontext->__ss.__rbp) #define CONTEXT_RSI(context) (((ucontext_t *) context)->uc_mcontext->__ss.__rsi) #define CONTEXT_RDI(context) (((ucontext_t *) context)->uc_mcontext->__ss.__rdi) +#define CONTEXT_R8(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r8) +#define CONTEXT_R9(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r9) +#define CONTEXT_R10(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r10) +#define CONTEXT_R11(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r11) +#define CONTEXT_R12(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r12) +#define CONTEXT_R13(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r13) +#define CONTEXT_R14(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r14) +#define CONTEXT_R15(context) (((ucontext_t *) context)->uc_mcontext->__ss.__r15) #elif defined(__DARWIN_UNIX03) && defined(CPU_i386) typedef void *CONTEXT_T; #define HAVE_CONTEXT_T 1 -#define CONTEXT_EIP(context) (*((unsigned long *) &((ucontext_t *) context)->uc_mcontext->__ss.__eip)) -#define CONTEXT_EAX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__eax) -#define CONTEXT_ECX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__ecx) -#define CONTEXT_EDX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__edx) -#define CONTEXT_EBX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__ebx) -#define CONTEXT_ESP(context) (*((unsigned long *) &((ucontext_t *) context)->uc_mcontext->__ss.__esp)) -#define CONTEXT_EBP(context) (((ucontext_t *) context)->uc_mcontext->__ss.__ebp) -#define CONTEXT_ESI(context) (((ucontext_t *) context)->uc_mcontext->__ss.__esi) -#define CONTEXT_EDI(context) (((ucontext_t *) context)->uc_mcontext->__ss.__edi) +#define CONTEXT_RIP(context) (*((unsigned long *) &((ucontext_t *) context)->uc_mcontext->__ss.__eip)) +#define CONTEXT_RAX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__eax) +#define CONTEXT_RCX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__ecx) +#define CONTEXT_RDX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__edx) +#define CONTEXT_RBX(context) (((ucontext_t *) context)->uc_mcontext->__ss.__ebx) +#define CONTEXT_RSP(context) (*((unsigned long *) &((ucontext_t *) context)->uc_mcontext->__ss.__esp)) +#define CONTEXT_RBP(context) (((ucontext_t *) context)->uc_mcontext->__ss.__ebp) +#define CONTEXT_RSI(context) (((ucontext_t *) context)->uc_mcontext->__ss.__esi) +#define CONTEXT_RDI(context) (((ucontext_t *) context)->uc_mcontext->__ss.__edi) #endif -#if defined(CPU_x86_64) -#ifdef CONTEXT_RIP #define CONTEXT_PC(context) CONTEXT_RIP(context) -#endif -#else -#ifdef CONTEXT_EIP -#define CONTEXT_PC(context) CONTEXT_EIP(context) -#endif -#endif /* FIXME: replace usage with bswap16, move fallback defition to header */ static inline uae_u16 swap16(uae_u16 x) @@ -153,33 +169,66 @@ static int delete_trigger(blockinfo *bi, void *pc) return 0; } -static bool decode_instruction(uae_u8 *pc, int *r, int *dir, int *size, int *len) +/* Opcode register id list: + * + * 8 Bit: 16 Bit: 32 Bit: + * + * 0: AL 0: AX 0: EAX + * 1: CL 1: CX 1: ECX + * 2: DL 2: DX 2: EDX + * 3: BL 3: BX 3: EBX + * 4: AH (SPL, if REX) 4: SP 4: ESP + * 5: CH (BPL, if REX) 5: BP 5: EBP + * 6: DH (SIL, if REX) 6: SI 6: ESI + * 7: BH (DIL, if REX) 7: DI 7: EDI + * 8: R8L 8: R8W 8: R8D + * 9: R9L 9: R9W 9: R9D + * 10: R10L 10: R10W 10: R10D + * 11: R11L 11: R11W 11: R11D + * 12: R12L 12: R12W 12: R12D + * 13: R13L 13: R13W 13: R13D + * 14: R14L 14: R14W 14: R14D + * 15: R15L 15: R15W 15: R15D + */ + +static bool decode_instruction( + uae_u8 *pc, int *r, int *dir, int *size, int *len, int *rex) { *r = -1; *size = 4; *dir = -1; *len = 0; + *rex = 0; #ifdef CPU_x86_64 + /* Skip address-size override prefix. */ if (*pc == 0x67) { - /* Skip address-size override prefix */ - pc += 1; - *len += 1; - } - if (*pc == 0x40) { - /* Skip REX prefix */ pc += 1; *len += 1; } #endif + /* Operand size override prefix. */ if (*pc == 0x66) { pc += 1; *size = 2; *len += 1; } +#ifdef CPU_x86_64 + /* Handle x86-64 REX prefix. */ + if ((pc[0] & 0xf0) == 0x40) { + *rex = pc[0]; + pc += 1; + *len += 1; + if (*rex & (1 << 3)) { + *size = 8; + /* 64-bit operand size not supported. */ + return 0; + } + } +#endif switch (pc[0]) { - case 0x8a: + case 0x8a: /* MOV r8, m8 */ if ((pc[1] & 0xc0) == 0x80) { *r = (pc[1] >> 3) & 7; *dir = SIG_READ; @@ -188,7 +237,7 @@ static bool decode_instruction(uae_u8 *pc, int *r, int *dir, int *size, int *len break; } break; - case 0x88: + case 0x88: /* MOV m8, r8 */ if ((pc[1] & 0xc0) == 0x80) { *r = (pc[1] >> 3) & 7; *dir = SIG_WRITE; @@ -197,7 +246,7 @@ static bool decode_instruction(uae_u8 *pc, int *r, int *dir, int *size, int *len break; } break; - case 0x8b: + case 0x8b: /* MOV r32, m32 */ switch (pc[1] & 0xc0) { case 0x80: *r = (pc[1] >> 3) & 7; @@ -218,8 +267,8 @@ static bool decode_instruction(uae_u8 *pc, int *r, int *dir, int *size, int *len break; } break; - case 0x89: - switch (pc[1]&0xc0) { + case 0x89: /* MOV m32, r32 */ + switch (pc[1] & 0xc0) { case 0x80: *r = (pc[1] >> 3) & 7; *dir = SIG_WRITE; @@ -238,10 +287,87 @@ static bool decode_instruction(uae_u8 *pc, int *r, int *dir, int *size, int *len } break; } - return r != 0; +#ifdef CPU_x86_64 + if (*rex & (1 << 2)) { + /* Use x86-64 extended registers R8..R15. */ + *r += 8; + } +#endif + return *r != -1; } #ifdef HAVE_CONTEXT_T + +static void *get_pr_from_context(CONTEXT_T context, int r, int size, int rex) +{ + switch (r) { + case 0: + return &(CONTEXT_RAX(context)); + case 1: + return &(CONTEXT_RCX(context)); + case 2: + return &(CONTEXT_RDX(context)); + case 3: + return &(CONTEXT_RBX(context)); + case 4: + if (size > 1 || rex) { + return NULL; + } else { + return (((uae_u8 *) &(CONTEXT_RAX(context))) + 1); /* AH */ + } + case 5: + if (size > 1 || rex) { + return &(CONTEXT_RBP(context)); + } else { + return (((uae_u8 *) &(CONTEXT_RCX(context))) + 1); /* CH */ + } + case 6: + if (size > 1 || rex) { + return &(CONTEXT_RSI(context)); + } else { + return (((uae_u8 *) &(CONTEXT_RDX(context))) + 1); /* DH */ + } + case 7: + if (size > 1 || rex) { + return &(CONTEXT_RDI(context)); + } else { + return (((uae_u8 *) &(CONTEXT_RBX(context))) + 1); /* BH */ + } +#ifdef CPU_x86_64 + case 8: + return &(CONTEXT_R8(context)); + case 9: + return &(CONTEXT_R9(context)); + case 10: + return &(CONTEXT_R10(context)); + case 11: + return &(CONTEXT_R11(context)); + case 12: + return &(CONTEXT_R12(context)); + case 13: + return &(CONTEXT_R13(context)); + case 14: + return &(CONTEXT_R14(context)); + case 15: + return &(CONTEXT_R15(context)); +#endif + default: + abort (); + } +} + +static void log_unhandled_access(uae_u8 *fault_pc) +{ + write_log(_T("JIT: Can't handle access PC=%p!\n"), fault_pc); + if (fault_pc) { + write_log(_T("JIT: Instruction bytes")); + for (int j = 0; j < 10; j++) { + write_log(_T(" %02x"), fault_pc[j]); + } + write_log(_T("\n")); + } +} + /* * Try to handle faulted memory access in compiled code * @@ -261,147 +387,111 @@ static int handle_access(uintptr_t fault_addr, CONTEXT_T context) } #endif - int r = -1; - int size = 4; - int dir = -1; - int len = 0; - #ifdef DEBUG_ACCESS - write_log (_T("JIT: Fault address is 0x%lx at PC=%p\n"), fault_addr, fault_pc); + write_log(_T("JIT: Fault address is 0x%lx at PC=%p\n"), fault_addr, fault_pc); #endif if (!canbang || !currprefs.cachesize) return 0; if (in_handler) - write_log (_T("JIT: Argh --- Am already in a handler. Shouldn't happen!\n")); + write_log(_T("JIT: Argh --- Am already in a handler. Shouldn't happen!\n")); + + if (fault_pc < compiled_code || fault_pc > current_compile_p) { + return 0; + } - if (canbang && fault_pc >= compiled_code && fault_pc <= current_compile_p) { - decode_instruction(fault_pc, &r, &dir, &size, &len); + int r = -1, size = 4, dir = -1, len = 0, rex = 0; + decode_instruction(fault_pc, &r, &dir, &size, &len, &rex); + if (r == -1) { + log_unhandled_access(fault_pc); + return 0; } - if (r!=-1) { - void *pr = NULL; #ifdef DEBUG_ACCESS - write_log (_T("JIT: Register was %d, direction was %d, size was %d\n"), - r, dir, size); + write_log (_T("JIT: Register was %d, direction was %d, size was %d\n"), + r, dir, size); #endif - switch(r) { -#if defined(CPU_x86_64) - case 0: pr = &(CONTEXT_RAX(context)); break; - case 1: pr = &(CONTEXT_RCX(context)); break; - case 2: pr = &(CONTEXT_RDX(context)); break; - case 3: pr = &(CONTEXT_RBX(context)); break; - case 4: pr = (size > 1) ? NULL - : (((uae_u8*)&(CONTEXT_RAX(context)))+1); - break; - case 5: pr = (size > 1) ? (void*) (&(CONTEXT_RBP(context))) - : (void*)(((uae_u8*)&(CONTEXT_RCX(context))) + 1); - break; - case 6: pr = (size > 1) ? (void*) (&(CONTEXT_RSI(context))) - : (void*)(((uae_u8*)&(CONTEXT_RDX(context))) + 1); - break; - case 7: pr = (size > 1) ? (void*) (&(CONTEXT_RDI(context))) - : (void*)(((uae_u8*)&(CONTEXT_RBX(context))) + 1); - break; -#else - case 0: pr = &(CONTEXT_EAX(context)); break; - case 1: pr = &(CONTEXT_ECX(context)); break; - case 2: pr = &(CONTEXT_EDX(context)); break; - case 3: pr = &(CONTEXT_EBX(context)); break; - case 4: pr = (size > 1) ? NULL - : (((uae_u8*)&(CONTEXT_EAX(context)))+1); - break; - case 5: pr = (size > 1) ? (void*) (&(CONTEXT_EBP(context))) - : (void*)(((uae_u8*)&(CONTEXT_ECX(context))) + 1); - break; - case 6: pr = (size > 1) ? (void*) (&(CONTEXT_ESI(context))) - : (void*)(((uae_u8*)&(CONTEXT_EDX(context))) + 1); - break; - case 7: pr = (size > 1) ? (void*) (&(CONTEXT_EDI(context))) - : (void*)(((uae_u8*)&(CONTEXT_EBX(context))) + 1); - break; -#endif - default: - abort (); - } - if (pr) { - { - uae_u32 addr = uae_p32(fault_addr) - uae_p32(NATMEM_OFFSET); + void *pr = get_pr_from_context(context, r, size, rex); + if (pr == NULL) { + log_unhandled_access(fault_pc); + return 0; + } + + uae_u32 addr = uae_p32(fault_addr) - uae_p32(NATMEM_OFFSET); #ifdef DEBUG_ACCESS - if ((addr >= 0x10000000 && addr < 0x40000000) || - (addr >= 0x50000000)) { - write_log (_T("JIT: Suspicious address 0x%x in SEGV handler.\n"), addr); - } + if ((addr >= 0x10000000 && addr < 0x40000000) || + (addr >= 0x50000000)) { + write_log (_T("JIT: Suspicious address 0x%x in SEGV handler.\n"), addr); + } #endif - uae_u8* original_target = target; - target = (uae_u8*) CONTEXT_PC(context); + uae_u8* original_target = target; + target = (uae_u8*) CONTEXT_PC(context); - uae_u8 vecbuf[5]; - for (int i = 0; i < 5; i++) { - vecbuf[i] = target[i]; - } - raw_jmp(uae_p32(veccode)); + uae_u8 vecbuf[5]; + for (int i = 0; i < 5; i++) { + vecbuf[i] = target[i]; + } + raw_jmp(uae_p32(veccode)); #ifdef DEBUG_ACCESS - write_log (_T("JIT: Create jump to %p\n"), veccode); - write_log (_T("JIT: Handled one access!\n")); -#endif - segvcount++; - - target = veccode; - - if (dir==SIG_READ) { - switch(size) { - case 1: raw_mov_b_ri(r,get_byte (addr)); break; - case 2: raw_mov_w_ri(r,swap16(get_word (addr))); break; - case 4: raw_mov_l_ri(r,swap32(get_long (addr))); break; - default: abort(); - } - } - else { /* write */ - switch(size) { - case 1: put_byte (addr,*((uae_u8*)pr)); break; - case 2: put_word (addr,swap16(*((uae_u16*)pr))); break; - case 4: put_long (addr,swap32(*((uae_u32*)pr))); break; - default: abort(); - } - } - for (int i = 0; i < 5; i++) { - raw_mov_b_mi(CONTEXT_PC(context) + i, vecbuf[i]); - } - raw_mov_l_mi(uae_p32(&in_handler), 0); - raw_jmp(uae_p32(CONTEXT_PC(context)) + len); - in_handler = 1; - target = original_target; - } - - if (delete_trigger(active, fault_pc)) { - return 1; - } - /* Not found in the active list. Might be a rom routine that - * is in the dormant list */ - if (delete_trigger(dormant, fault_pc)) { - return 1; - } -#ifdef DEBUG_ACCESS - write_log (_T("JIT: Huh? Could not find trigger!\n")); + write_log(_T("JIT: Create jump to %p\n"), veccode); + write_log(_T("JIT: Handled one access!\n")); #endif - return 1; + segvcount++; + + target = veccode; + if (dir == SIG_READ) { + switch (size) { + case 1: + raw_mov_b_ri(r, get_byte(addr)); + break; + case 2: + raw_mov_w_ri(r, swap16(get_word(addr))); + break; + case 4: + raw_mov_l_ri(r, swap32(get_long(addr))); + break; + default: + abort(); + } + } else { + switch (size) { + case 1: + put_byte(addr, *((uae_u8 *) pr)); + break; + case 2: + put_word(addr, swap16(*((uae_u16 *) pr))); + break; + case 4: + put_long(addr, swap32(*((uae_u32 *) pr))); + break; + default: abort(); } } + for (int i = 0; i < 5; i++) { + raw_mov_b_mi(CONTEXT_PC(context) + i, vecbuf[i]); + } + raw_mov_l_mi(uae_p32(&in_handler), 0); + raw_jmp(uae_p32(CONTEXT_PC(context)) + len); - write_log (_T("JIT: Can't handle access PC=%p!\n"), fault_pc); - if (fault_pc) { - write_log (_T("JIT: Instruction bytes")); - for (int j = 0; j < 10; j++) { - write_log (_T(" %02x"), fault_pc[j]); - } - write_log (_T("\n")); + in_handler = 1; + target = original_target; + if (delete_trigger(active, fault_pc)) { + return 1; } - return 0; + /* Not found in the active list. Might be a rom routine that + * is in the dormant list */ + if (delete_trigger(dormant, fault_pc)) { + return 1; + } +#ifdef DEBUG_ACCESS + write_log (_T("JIT: Huh? Could not find trigger!\n")); +#endif + return 1; } + #endif /* CONTEXT_T */ #ifdef _WIN32 -- 2.47.3