1c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner/* 2c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * x86 memory access helpers 3c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * 4c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * Copyright (c) 2003 Fabrice Bellard 5c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * 6c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * This library is free software; you can redistribute it and/or 7c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * modify it under the terms of the GNU Lesser General Public 8c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * License as published by the Free Software Foundation; either 9c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * version 2 of the License, or (at your option) any later version. 10c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * 11c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * This library is distributed in the hope that it will be useful, 12c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of 13c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * Lesser General Public License for more details. 15c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * 16c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * You should have received a copy of the GNU Lesser General Public 17c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner */ 19c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 20c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#include "cpu.h" 21c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#include "helper.h" 22c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 23c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#if !defined(CONFIG_USER_ONLY) 24c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#include "exec/softmmu_exec.h" 25c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#endif /* !defined(CONFIG_USER_ONLY) */ 26c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 27c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner/* broken thread support */ 28c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 29c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnerstatic spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; 30c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 31c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnervoid helper_lock(void) 32c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner{ 33c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner spin_lock(&global_cpu_lock); 34c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner} 35c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 36c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnervoid helper_unlock(void) 37c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner{ 38c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner spin_unlock(&global_cpu_lock); 39c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner} 40c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 41c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnervoid helper_cmpxchg8b(CPUX86State *env, target_ulong a0) 42c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner{ 43c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner uint64_t d; 44c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner int eflags; 45c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 46c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner eflags = helper_cc_compute_all(env, CC_OP); 47c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner d = cpu_ldq_data(env, a0); 48c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) { 49c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner cpu_stq_data(env, a0, ((uint64_t)ECX << 32) | (uint32_t)EBX); 50c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner eflags |= CC_Z; 51c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } else { 52c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner /* always do the store */ 53c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner cpu_stq_data(env, a0, d); 54c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner EDX = (uint32_t)(d >> 32); 55c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner EAX = (uint32_t)d; 56c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner eflags &= ~CC_Z; 57c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } 58c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner CC_SRC = eflags; 59c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner} 60c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 61c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#ifdef TARGET_X86_64 62c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnervoid helper_cmpxchg16b(CPUX86State *env, target_ulong a0) 63c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner{ 64c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner uint64_t d0, d1; 65c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner int eflags; 66c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 67c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner if ((a0 & 0xf) != 0) 68c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner raise_exception(env, EXCP0D_GPF); 69c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner eflags = helper_cc_compute_all(env, CC_OP); 70c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner d0 = cpu_ldq_data(env, a0); 71c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner d1 = cpu_ldq_data(env, a0 + 8); 72c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner if (d0 == EAX && d1 == EDX) { 73c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner cpu_stq_data(env, a0, EBX); 74c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner cpu_stq_data(env, a0 + 8, ECX); 75c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner eflags |= CC_Z; 76c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } else { 77c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner /* always do the store */ 78c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner cpu_stq_data(env, a0, d0); 79c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner cpu_stq_data(env, a0 + 8, d1); 80c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner EDX = d1; 81c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner EAX = d0; 82c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner eflags &= ~CC_Z; 83c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } 84c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner CC_SRC = eflags; 85c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner} 86c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#endif 87c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 88c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnervoid helper_boundw(CPUX86State *env, target_ulong a0, int v) 89c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner{ 90c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner int low, high; 91c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner low = cpu_ldsw_data(env, a0); 92c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner high = cpu_ldsw_data(env, a0 + 2); 93c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner v = (int16_t)v; 94c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner if (v < low || v > high) { 95c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner raise_exception(env, EXCP05_BOUND); 96c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } 97c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner} 98c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 99c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnervoid helper_boundl(CPUX86State *env, target_ulong a0, int v) 100c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner{ 101c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner int low, high; 102c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner low = cpu_ldl_data(env, a0); 103c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner high = cpu_ldl_data(env, a0 + 4); 104c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner if (v < low || v > high) { 105c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner raise_exception(env, EXCP05_BOUND); 106c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } 107c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner} 108c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 109c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#if !defined(CONFIG_USER_ONLY) 110c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 111c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#define MMUSUFFIX _mmu 112c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 113c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#define SHIFT 0 114c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#include "exec/softmmu_template.h" 115c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 116c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#define SHIFT 1 117c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#include "exec/softmmu_template.h" 118c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 119c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#define SHIFT 2 120c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#include "exec/softmmu_template.h" 121c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 122c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#define SHIFT 3 123c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#include "exec/softmmu_template.h" 124c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 125c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#endif 126c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 127c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#if !defined(CONFIG_USER_ONLY) 128c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner/* try to fill the TLB and return an exception if error. If retaddr is 129c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner NULL, it means that the function was called in C code (i.e. not 130c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner from generated code or from helper.c) */ 131c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner/* XXX: fix it to restore all registers */ 132c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turnervoid tlb_fill(CPUX86State* env, target_ulong addr, int is_write, int mmu_idx, 133c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner uintptr_t retaddr) 134c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner{ 135c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner int ret; 136c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner 137c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx); 138c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner if (ret) { 139c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner if (retaddr) { 140c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner /* now we have a real cpu fault */ 141c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner cpu_restore_state(env, retaddr); 142c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } 143c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner raise_exception_err(env, env->exception_index, env->error_code); 144c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner } 145c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner} 146c0a7e0d8a37ad5579ba5359d498285874af72f43David 'Digit' Turner#endif 147