Search
lxdream.org :: lxdream/src/xlat/x86/amd64abi.h :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/x86/amd64abi.h
changeset 992:7c15f8a71995
prev991:60c7fab9c880
next995:eb9d43e8aa08
author nkeynes
date Wed Mar 04 23:27:59 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Move ABI headers to xlat/x86 as well (and finally rename erroneously named ia64abi to amd64abi)
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/xlat/x86/amd64abi.h Wed Mar 04 23:27:59 2009 +0000
1.3 @@ -0,0 +1,318 @@
1.4 +/**
1.5 + * $Id$
1.6 + *
1.7 + * Provides the implementation for the AMD64 ABI (eg prologue, epilogue, and
1.8 + * calling conventions)
1.9 + *
1.10 + * Copyright (c) 2007 Nathan Keynes.
1.11 + *
1.12 + * This program is free software; you can redistribute it and/or modify
1.13 + * it under the terms of the GNU General Public License as published by
1.14 + * the Free Software Foundation; either version 2 of the License, or
1.15 + * (at your option) any later version.
1.16 + *
1.17 + * This program is distributed in the hope that it will be useful,
1.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.20 + * GNU General Public License for more details.
1.21 + */
1.22 +
1.23 +#ifndef lxdream_ia64abi_H
1.24 +#define lxdream_ia64abi_H 1
1.25 +
1.26 +#include <unwind.h>
1.27 +
1.28 +#define load_ptr( reg, ptr ) load_imm64( reg, (uint64_t)ptr );
1.29 +
1.30 +static inline void decode_address( int addr_reg )
1.31 +{
1.32 + uintptr_t base = (sh4r.xlat_sh4_mode&SR_MD) ? (uintptr_t)sh4_address_space : (uintptr_t)sh4_user_address_space;
1.33 + MOVL_r32_r32( addr_reg, REG_RCX );
1.34 + SHRL_imm_r32( 12, REG_RCX );
1.35 + MOVP_immptr_rptr( base, REG_RDI );
1.36 + MOVP_sib_rptr(3, REG_RCX, REG_RDI, 0, REG_RCX);
1.37 +}
1.38 +
1.39 +/**
1.40 + * Note: clobbers EAX to make the indirect call - this isn't usually
1.41 + * a problem since the callee will usually clobber it anyway.
1.42 + * Size: 12 bytes
1.43 + */
1.44 +#define CALL_FUNC0_SIZE 12
1.45 +static inline void call_func0( void *ptr )
1.46 +{
1.47 + MOVQ_imm64_r64((uint64_t)ptr, REG_RAX);
1.48 + CALL_r32(REG_RAX);
1.49 +}
1.50 +
1.51 +static inline void call_func1( void *ptr, int arg1 )
1.52 +{
1.53 + MOVQ_r64_r64(arg1, REG_RDI);
1.54 + call_func0(ptr);
1.55 +}
1.56 +
1.57 +static inline void call_func1_exc( void *ptr, int arg1, int pc )
1.58 +{
1.59 + MOVQ_r64_r64(arg1, REG_RDI);
1.60 + MOVP_immptr_rptr(0, REG_RSI);
1.61 + sh4_x86_add_backpatch( xlat_output, pc, -2 );
1.62 + call_func0(ptr);
1.63 +}
1.64 +
1.65 +static inline void call_func1_r32disp8( int preg, uint32_t disp8, int arg1 )
1.66 +{
1.67 + MOVQ_r64_r64(arg1, REG_RDI);
1.68 + CALL_r32disp(preg, disp8);
1.69 +}
1.70 +
1.71 +static inline void call_func1_r32disp8_exc( int preg, uint32_t disp8, int arg1, int pc )
1.72 +{
1.73 + MOVQ_r64_r64(arg1, REG_RDI);
1.74 + MOVP_immptr_rptr(0, REG_RSI);
1.75 + sh4_x86_add_backpatch( xlat_output, pc, -2 );
1.76 + CALL_r32disp(preg, disp8);
1.77 +}
1.78 +
1.79 +static inline void call_func2( void *ptr, int arg1, int arg2 )
1.80 +{
1.81 + MOVQ_r64_r64(arg1, REG_RDI);
1.82 + MOVQ_r64_r64(arg2, REG_RSI);
1.83 + call_func0(ptr);
1.84 +}
1.85 +
1.86 +static inline void call_func2_r32disp8( int preg, uint32_t disp8, int arg1, int arg2 )
1.87 +{
1.88 + MOVQ_r64_r64(arg1, REG_RDI);
1.89 + MOVQ_r64_r64(arg2, REG_RSI);
1.90 + CALL_r32disp(preg, disp8);
1.91 +}
1.92 +
1.93 +static inline void call_func2_r32disp8_exc( int preg, uint32_t disp8, int arg1, int arg2, int pc )
1.94 +{
1.95 + MOVQ_r64_r64(arg1, REG_RDI);
1.96 + MOVQ_r64_r64(arg2, REG_RSI);
1.97 + MOVP_immptr_rptr(0, REG_RDX);
1.98 + sh4_x86_add_backpatch( xlat_output, pc, -2 );
1.99 + CALL_r32disp(preg, disp8);
1.100 +}
1.101 +
1.102 +
1.103 +
1.104 +/**
1.105 + * Emit the 'start of block' assembly. Sets up the stack frame and save
1.106 + * SI/DI as required
1.107 + */
1.108 +void enter_block( )
1.109 +{
1.110 + PUSH_r32(REG_RBP);
1.111 + load_ptr( REG_RBP, ((uint8_t *)&sh4r) + 128 );
1.112 + // Minimum aligned allocation is 16 bytes
1.113 + SUBQ_imms_r64( 16, REG_RSP );
1.114 +}
1.115 +
1.116 +static inline void exit_block( )
1.117 +{
1.118 + ADDQ_imms_r64( 16, REG_RSP );
1.119 + POP_r32(REG_RBP);
1.120 + RET();
1.121 +}
1.122 +
1.123 +/**
1.124 + * Exit the block with sh4r.pc already written
1.125 + */
1.126 +void exit_block_pcset( sh4addr_t pc )
1.127 +{
1.128 + load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.129 + ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
1.130 + load_spreg( REG_RAX, R_PC );
1.131 + if( sh4_x86.tlb_on ) {
1.132 + call_func1(xlat_get_code_by_vma,REG_RAX);
1.133 + } else {
1.134 + call_func1(xlat_get_code,REG_RAX);
1.135 + }
1.136 + exit_block();
1.137 +}
1.138 +
1.139 +/**
1.140 + * Exit the block with sh4r.new_pc written with the target address
1.141 + */
1.142 +void exit_block_newpcset( sh4addr_t pc )
1.143 +{
1.144 + load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.145 + ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
1.146 + load_spreg( REG_RAX, R_NEW_PC );
1.147 + store_spreg( REG_RAX, R_PC );
1.148 + if( sh4_x86.tlb_on ) {
1.149 + call_func1(xlat_get_code_by_vma,REG_RAX);
1.150 + } else {
1.151 + call_func1(xlat_get_code,REG_RAX);
1.152 + }
1.153 + exit_block();
1.154 +}
1.155 +
1.156 +#define EXIT_BLOCK_SIZE(pc) (25 + (IS_IN_ICACHE(pc)?10:CALL_FUNC1_SIZE))
1.157 +/**
1.158 + * Exit the block to an absolute PC
1.159 + */
1.160 +void exit_block_abs( sh4addr_t pc, sh4addr_t endpc )
1.161 +{
1.162 + load_imm32( REG_RCX, pc ); // 5
1.163 + store_spreg( REG_RCX, REG_OFFSET(pc) ); // 3
1.164 + if( IS_IN_ICACHE(pc) ) {
1.165 + MOVP_moffptr_rax( xlat_get_lut_entry(pc) );
1.166 + ANDQ_imms_r64( 0xFFFFFFFC, REG_RAX ); // 4
1.167 + } else if( sh4_x86.tlb_on ) {
1.168 + call_func1(xlat_get_code_by_vma, REG_RCX);
1.169 + } else {
1.170 + call_func1(xlat_get_code,REG_RCX);
1.171 + }
1.172 + load_imm32( REG_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.173 + ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
1.174 + exit_block();
1.175 +}
1.176 +
1.177 +
1.178 +#define EXIT_BLOCK_REL_SIZE(pc) (28 + (IS_IN_ICACHE(pc)?10:CALL_FUNC1_SIZE))
1.179 +
1.180 +/**
1.181 + * Exit the block to a relative PC
1.182 + */
1.183 +void exit_block_rel( sh4addr_t pc, sh4addr_t endpc )
1.184 +{
1.185 + load_imm32( REG_ECX, pc - sh4_x86.block_start_pc ); // 5
1.186 + ADDL_rbpdisp_r32( R_PC, REG_ECX );
1.187 + store_spreg( REG_ECX, REG_OFFSET(pc) ); // 3
1.188 + if( IS_IN_ICACHE(pc) ) {
1.189 + MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
1.190 + ANDQ_imms_r64( 0xFFFFFFFC, REG_RAX ); // 4
1.191 + } else if( sh4_x86.tlb_on ) {
1.192 + call_func1(xlat_get_code_by_vma,REG_RCX);
1.193 + } else {
1.194 + call_func1(xlat_get_code,REG_RCX);
1.195 + }
1.196 + load_imm32( REG_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.197 + ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
1.198 + exit_block();
1.199 +}
1.200 +
1.201 +/**
1.202 + * Exit unconditionally with a general exception
1.203 + */
1.204 +void exit_block_exc( int code, sh4addr_t pc )
1.205 +{
1.206 + load_imm32( REG_ECX, pc - sh4_x86.block_start_pc ); // 5
1.207 + ADDL_r32_rbpdisp( REG_ECX, R_PC );
1.208 + load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.209 + ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
1.210 + load_imm32( REG_RAX, code );
1.211 + call_func1( sh4_raise_exception, REG_RAX );
1.212 +
1.213 + load_spreg( REG_RAX, R_PC );
1.214 + if( sh4_x86.tlb_on ) {
1.215 + call_func1(xlat_get_code_by_vma,REG_RAX);
1.216 + } else {
1.217 + call_func1(xlat_get_code,REG_RAX);
1.218 + }
1.219 +
1.220 + exit_block();
1.221 +}
1.222 +
1.223 +
1.224 +/**
1.225 + * Write the block trailer (exception handling block)
1.226 + */
1.227 +void sh4_translate_end_block( sh4addr_t pc ) {
1.228 + if( sh4_x86.branch_taken == FALSE ) {
1.229 + // Didn't exit unconditionally already, so write the termination here
1.230 + exit_block_rel( pc, pc );
1.231 + }
1.232 + if( sh4_x86.backpatch_posn != 0 ) {
1.233 + unsigned int i;
1.234 + // Raise exception
1.235 + uint8_t *end_ptr = xlat_output;
1.236 + MOVL_r32_r32( REG_RDX, REG_RCX );
1.237 + ADDL_r32_r32( REG_RDX, REG_RCX );
1.238 + ADDL_r32_rbpdisp( REG_RCX, R_PC );
1.239 + MOVL_moffptr_eax( &sh4_cpu_period );
1.240 + MULL_r32( REG_RDX );
1.241 + ADDL_r32_rbpdisp( REG_RAX, REG_OFFSET(slice_cycle) );
1.242 +
1.243 + call_func0( sh4_raise_exception );
1.244 + load_spreg( REG_RAX, R_PC );
1.245 + if( sh4_x86.tlb_on ) {
1.246 + call_func1(xlat_get_code_by_vma,REG_RAX);
1.247 + } else {
1.248 + call_func1(xlat_get_code,REG_RAX);
1.249 + }
1.250 + exit_block();
1.251 +
1.252 + // Exception already raised - just cleanup
1.253 + uint8_t *preexc_ptr = xlat_output;
1.254 + MOVL_r32_r32( REG_EDX, REG_ECX );
1.255 + ADDL_r32_r32( REG_EDX, REG_ECX );
1.256 + ADDL_r32_rbpdisp( REG_ECX, R_SPC );
1.257 + MOVL_moffptr_eax( &sh4_cpu_period );
1.258 + MULL_r32( REG_EDX );
1.259 + ADDL_r32_rbpdisp( REG_EAX, REG_OFFSET(slice_cycle) );
1.260 + load_spreg( REG_RDI, R_PC );
1.261 + if( sh4_x86.tlb_on ) {
1.262 + call_func0(xlat_get_code_by_vma);
1.263 + } else {
1.264 + call_func0(xlat_get_code);
1.265 + }
1.266 + exit_block();
1.267 +
1.268 + for( i=0; i< sh4_x86.backpatch_posn; i++ ) {
1.269 + uint32_t *fixup_addr = (uint32_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset];
1.270 + if( sh4_x86.backpatch_list[i].exc_code < 0 ) {
1.271 + if( sh4_x86.backpatch_list[i].exc_code == -2 ) {
1.272 + *((uintptr_t *)fixup_addr) = (uintptr_t)xlat_output;
1.273 + } else {
1.274 + *fixup_addr = xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
1.275 + }
1.276 + load_imm32( REG_RDX, sh4_x86.backpatch_list[i].fixup_icount );
1.277 + int rel = preexc_ptr - xlat_output;
1.278 + JMP_prerel(rel);
1.279 + } else {
1.280 + *fixup_addr = xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
1.281 + load_imm32( REG_RDI, sh4_x86.backpatch_list[i].exc_code );
1.282 + load_imm32( REG_RDX, sh4_x86.backpatch_list[i].fixup_icount );
1.283 + int rel = end_ptr - xlat_output;
1.284 + JMP_prerel(rel);
1.285 + }
1.286 + }
1.287 + }
1.288 +}
1.289 +
1.290 +struct UnwindInfo {
1.291 + uintptr_t block_start;
1.292 + uintptr_t block_end;
1.293 + void *pc;
1.294 +};
1.295 +
1.296 +_Unwind_Reason_Code xlat_check_frame( struct _Unwind_Context *context, void *arg )
1.297 +{
1.298 + struct UnwindInfo *info = arg;
1.299 + void *pc = (void *)_Unwind_GetIP(context);
1.300 + if( ((uintptr_t)pc) >= info->block_start && ((uintptr_t)pc) < info->block_end ) {
1.301 + info->pc = pc;
1.302 + return _URC_NORMAL_STOP;
1.303 + }
1.304 +
1.305 + return _URC_NO_REASON;
1.306 +}
1.307 +
1.308 +void *xlat_get_native_pc( void *code, uint32_t code_size )
1.309 +{
1.310 + struct _Unwind_Exception exc;
1.311 + struct UnwindInfo info;
1.312 +
1.313 + info.pc = NULL;
1.314 + info.block_start = (uintptr_t)code;
1.315 + info.block_end = info.block_start + code_size;
1.316 + void *result = NULL;
1.317 + _Unwind_Backtrace( xlat_check_frame, &info );
1.318 + return info.pc;
1.319 +}
1.320 +
1.321 +#endif /* !lxdream_ia64abi_H */
.