186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * i386 helpers 386797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 486797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Copyright (c) 2003 Fabrice Bellard 586797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * This library is free software; you can redistribute it and/or 786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * modify it under the terms of the GNU Lesser General Public 886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * License as published by the Free Software Foundation; either 986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * version 2 of the License, or (at your option) any later version. 1086797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 1186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * This library is distributed in the hope that it will be useful, 1286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * but WITHOUT ANY WARRANTY; without even the implied warranty of 1386797937017f52bff088d02edf64fb931177a7eaJun Nakajima * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1486797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Lesser General Public License for more details. 1586797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 1686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * You should have received a copy of the GNU Lesser General Public 1786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * License along with this library; if not, write to the Free Software 1886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA 1986797937017f52bff088d02edf64fb931177a7eaJun Nakajima */ 2086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define CPU_NO_GLOBAL_REGS 2186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "exec.h" 2286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "exec-all.h" 2386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "host-utils.h" 2486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 2586797937017f52bff088d02edf64fb931177a7eaJun Nakajima//#define DEBUG_PCALL 2686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 2786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 2886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_PCALL 2986797937017f52bff088d02edf64fb931177a7eaJun Nakajima# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) 3086797937017f52bff088d02edf64fb931177a7eaJun Nakajima# define LOG_PCALL_STATE(env) \ 3186797937017f52bff088d02edf64fb931177a7eaJun Nakajima log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP) 3286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 3386797937017f52bff088d02edf64fb931177a7eaJun Nakajima# define LOG_PCALL(...) do { } while (0) 3486797937017f52bff088d02edf64fb931177a7eaJun Nakajima# define LOG_PCALL_STATE(env) do { } while (0) 3586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 3686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 3786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 3886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if 0 3986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define raise_exception_err(a, b)\ 4086797937017f52bff088d02edf64fb931177a7eaJun Nakajimado {\ 4186797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log("raise_exception line=%d\n", __LINE__);\ 4286797937017f52bff088d02edf64fb931177a7eaJun Nakajima (raise_exception_err)(a, b);\ 4386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} while (0) 4486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 4586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 4686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic const uint8_t parity_table[256] = { 4786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 4886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 4986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 5086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 5186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 5286797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 5386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 5486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 5586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 5686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 5786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 5886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 5986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 6086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 6186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 6286797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 6386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 6486797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 6586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 6686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 6786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 6886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 6986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 7086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 7186797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 7286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 7386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 7486797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 7586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 7686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 7786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 7886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, 7986797937017f52bff088d02edf64fb931177a7eaJun Nakajima}; 8086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 8186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* modulo 17 table */ 8286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic const uint8_t rclw_table[32] = { 8386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 1, 2, 3, 4, 5, 6, 7, 8486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 8, 9,10,11,12,13,14,15, 8586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 16, 0, 1, 2, 3, 4, 5, 6, 8686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 7, 8, 9,10,11,12,13,14, 8786797937017f52bff088d02edf64fb931177a7eaJun Nakajima}; 8886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 8986797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* modulo 9 table */ 9086797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic const uint8_t rclb_table[32] = { 9186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 1, 2, 3, 4, 5, 6, 7, 9286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 8, 0, 1, 2, 3, 4, 5, 6, 9386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 7, 8, 0, 1, 2, 3, 4, 5, 9486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 6, 7, 8, 0, 1, 2, 3, 4, 9586797937017f52bff088d02edf64fb931177a7eaJun Nakajima}; 9686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 9786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic const CPU86_LDouble f15rk[7] = 9886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 9986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0.00000000000000000000L, 10086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 1.00000000000000000000L, 10186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 3.14159265358979323851L, /*pi*/ 10286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0.30102999566398119523L, /*lg2*/ 10386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0.69314718055994530943L, /*ln2*/ 10486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 1.44269504088896340739L, /*l2e*/ 10586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 3.32192809488736234781L, /*l2t*/ 10686797937017f52bff088d02edf64fb931177a7eaJun Nakajima}; 10786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 10886797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* broken thread support */ 10986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 11086797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; 11186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 11286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_lock(void) 11386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 11486797937017f52bff088d02edf64fb931177a7eaJun Nakajima spin_lock(&global_cpu_lock); 11586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 11686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 11786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_unlock(void) 11886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 11986797937017f52bff088d02edf64fb931177a7eaJun Nakajima spin_unlock(&global_cpu_lock); 12086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 12186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 12286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_write_eflags(target_ulong t0, uint32_t update_mask) 12386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 12486797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(t0, update_mask); 12586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 12686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 12786797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_read_eflags(void) 12886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 12986797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t eflags; 13086797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 13186797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= (DF & DF_MASK); 13286797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= env->eflags & ~(VM_MASK | RF_MASK); 13386797937017f52bff088d02edf64fb931177a7eaJun Nakajima return eflags; 13486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 13586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 13686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* return non zero if error */ 13786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, 13886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int selector) 13986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 14086797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 14186797937017f52bff088d02edf64fb931177a7eaJun Nakajima int index; 14286797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 14386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 14486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (selector & 0x4) 14586797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->ldt; 14686797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 14786797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->gdt; 14886797937017f52bff088d02edf64fb931177a7eaJun Nakajima index = selector & ~7; 14986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((index + 7) > dt->limit) 15086797937017f52bff088d02edf64fb931177a7eaJun Nakajima return -1; 15186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + index; 15286797937017f52bff088d02edf64fb931177a7eaJun Nakajima *e1_ptr = ldl_kernel(ptr); 15386797937017f52bff088d02edf64fb931177a7eaJun Nakajima *e2_ptr = ldl_kernel(ptr + 4); 15486797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 15586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 15686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 15786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) 15886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 15986797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int limit; 16086797937017f52bff088d02edf64fb931177a7eaJun Nakajima limit = (e1 & 0xffff) | (e2 & 0x000f0000); 16186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_G_MASK) 16286797937017f52bff088d02edf64fb931177a7eaJun Nakajima limit = (limit << 12) | 0xfff; 16386797937017f52bff088d02edf64fb931177a7eaJun Nakajima return limit; 16486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 16586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 16686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) 16786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 16886797937017f52bff088d02edf64fb931177a7eaJun Nakajima return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); 16986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 17086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 17186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) 17286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 17386797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->base = get_seg_base(e1, e2); 17486797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->limit = get_seg_limit(e1, e2); 17586797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->flags = e2; 17686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 17786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 17886797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* init the segment cache in vm86 mode. */ 17986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void load_seg_vm(int seg, int selector) 18086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 18186797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector &= 0xffff; 18286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, seg, selector, 18386797937017f52bff088d02edf64fb931177a7eaJun Nakajima (selector << 4), 0xffff, 0); 18486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 18586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 18686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 18786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t *esp_ptr, int dpl) 18886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 18986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int type, index, shift; 19086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 19186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if 0 19286797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 19386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i; 19486797937017f52bff088d02edf64fb931177a7eaJun Nakajima printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); 19586797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i=0;i<env->tr.limit;i++) { 19686797937017f52bff088d02edf64fb931177a7eaJun Nakajima printf("%02x ", env->tr.base[i]); 19786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((i & 7) == 7) printf("\n"); 19886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 19986797937017f52bff088d02edf64fb931177a7eaJun Nakajima printf("\n"); 20086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 20186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 20286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 20386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->tr.flags & DESC_P_MASK)) 20486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_abort(env, "invalid tss"); 20586797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; 20686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((type & 7) != 1) 20786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_abort(env, "invalid tss type"); 20886797937017f52bff088d02edf64fb931177a7eaJun Nakajima shift = type >> 3; 20986797937017f52bff088d02edf64fb931177a7eaJun Nakajima index = (dpl * 4 + 2) << shift; 21086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (index + (4 << shift) - 1 > env->tr.limit) 21186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); 21286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 0) { 21386797937017f52bff088d02edf64fb931177a7eaJun Nakajima *esp_ptr = lduw_kernel(env->tr.base + index); 21486797937017f52bff088d02edf64fb931177a7eaJun Nakajima *ss_ptr = lduw_kernel(env->tr.base + index + 2); 21586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 21686797937017f52bff088d02edf64fb931177a7eaJun Nakajima *esp_ptr = ldl_kernel(env->tr.base + index); 21786797937017f52bff088d02edf64fb931177a7eaJun Nakajima *ss_ptr = lduw_kernel(env->tr.base + index + 4); 21886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 21986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 22086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 22186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: merge with load_seg() */ 22286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void tss_load_seg(int seg_reg, int selector) 22386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 22486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2; 22586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int rpl, dpl, cpl; 22686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 22786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) != 0) { 22886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 22986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 23086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK)) 23186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 23286797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = selector & 3; 23386797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 23486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 23586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (seg_reg == R_CS) { 23686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_CS_MASK)) 23786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 23886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: is it correct ? */ 23986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl != rpl) 24086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 24186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_C_MASK) && dpl > rpl) 24286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 24386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else if (seg_reg == R_SS) { 24486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* SS must be writable data */ 24586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) 24686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 24786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl != cpl || dpl != rpl) 24886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 24986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 25086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* not readable code */ 25186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) 25286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 25386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* if data or non conforming code, checks the rights */ 25486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { 25586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 25686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 25786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 25886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 25986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 26086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 26186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, seg_reg, selector, 26286797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 26386797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), 26486797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2); 26586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 26686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (seg_reg == R_SS || seg_reg == R_CS) 26786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, selector & 0xfffc); 26886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 26986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 27086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 27186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SWITCH_TSS_JMP 0 27286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SWITCH_TSS_IRET 1 27386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SWITCH_TSS_CALL 2 27486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 27586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: restore CPU state in registers (PowerPC case) */ 27686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void switch_tss(int tss_selector, 27786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, uint32_t e2, int source, 27886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t next_eip) 27986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 28086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; 28186797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong tss_base; 28286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t new_regs[8], new_segs[6]; 28386797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; 28486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t old_eflags, eflags_mask; 28586797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 28686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int index; 28786797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 28886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 28986797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0xf; 29086797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); 29186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 29286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* if task gate, we read the TSS segment and we load it */ 29386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type == 5) { 29486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 29586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); 29686797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_selector = e1 >> 16; 29786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (tss_selector & 4) 29886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); 29986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, tss_selector) != 0) 30086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); 30186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_S_MASK) 30286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); 30386797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0xf; 30486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((type & 7) != 1) 30586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); 30686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 30786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 30886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 30986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); 31086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 31186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type & 8) 31286797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_limit_max = 103; 31386797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 31486797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_limit_max = 43; 31586797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_limit = get_seg_limit(e1, e2); 31686797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_base = get_seg_base(e1, e2); 31786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((tss_selector & 4) != 0 || 31886797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_limit < tss_limit_max) 31986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); 32086797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; 32186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (old_type & 8) 32286797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_tss_limit_max = 103; 32386797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 32486797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_tss_limit_max = 43; 32586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 32686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* read all the registers from the new TSS */ 32786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type & 8) { 32886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 32 bit */ 32986797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_cr3 = ldl_kernel(tss_base + 0x1c); 33086797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eip = ldl_kernel(tss_base + 0x20); 33186797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eflags = ldl_kernel(tss_base + 0x24); 33286797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 8; i++) 33386797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4)); 33486797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) 33586797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4)); 33686797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_ldt = lduw_kernel(tss_base + 0x60); 33786797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_trap = ldl_kernel(tss_base + 0x64); 33886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 33986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bit */ 34086797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_cr3 = 0; 34186797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eip = lduw_kernel(tss_base + 0x0e); 34286797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eflags = lduw_kernel(tss_base + 0x10); 34386797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 8; i++) 34486797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000; 34586797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 4; i++) 34686797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4)); 34786797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_ldt = lduw_kernel(tss_base + 0x2a); 34886797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_segs[R_FS] = 0; 34986797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_segs[R_GS] = 0; 35086797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_trap = 0; 35186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 35286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 35386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* NOTE: we must avoid memory exceptions during the task switch, 35486797937017f52bff088d02edf64fb931177a7eaJun Nakajima so we make dummy accesses before */ 35586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: it can still fail in some cases, so a bigger hack is 35686797937017f52bff088d02edf64fb931177a7eaJun Nakajima necessary to valid the TLB after having done the accesses */ 35786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 35886797937017f52bff088d02edf64fb931177a7eaJun Nakajima v1 = ldub_kernel(env->tr.base); 35986797937017f52bff088d02edf64fb931177a7eaJun Nakajima v2 = ldub_kernel(env->tr.base + old_tss_limit_max); 36086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stb_kernel(env->tr.base, v1); 36186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stb_kernel(env->tr.base + old_tss_limit_max, v2); 36286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 36386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* clear busy bit (it is restartable) */ 36486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { 36586797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 36686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e2; 36786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = env->gdt.base + (env->tr.selector & ~7); 36886797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 36986797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 &= ~DESC_TSS_BUSY_MASK; 37086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(ptr + 4, e2); 37186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 37286797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eflags = compute_eflags(); 37386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (source == SWITCH_TSS_IRET) 37486797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eflags &= ~NT_MASK; 37586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 37686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* save the current state in the old TSS */ 37786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type & 8) { 37886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 32 bit */ 37986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + 0x20, next_eip); 38086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + 0x24, old_eflags); 38186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX); 38286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX); 38386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX); 38486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX); 38586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP); 38686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP); 38786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI); 38886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI); 38986797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) 39086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); 39186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 39286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bit */ 39386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + 0x0e, next_eip); 39486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + 0x10, old_eflags); 39586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX); 39686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX); 39786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX); 39886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX); 39986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP); 40086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP); 40186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI); 40286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI); 40386797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 4; i++) 40486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); 40586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 40686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 40786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* now if an exception occurs, it will occurs in the next task 40886797937017f52bff088d02edf64fb931177a7eaJun Nakajima context */ 40986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 41086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (source == SWITCH_TSS_CALL) { 41186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(tss_base, env->tr.selector); 41286797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eflags |= NT_MASK; 41386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 41486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 41586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* set busy bit */ 41686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { 41786797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 41886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e2; 41986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = env->gdt.base + (tss_selector & ~7); 42086797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 42186797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 |= DESC_TSS_BUSY_MASK; 42286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(ptr + 4, e2); 42386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 42486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 42586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* set the new CPU state */ 42686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* from this point, any exception which occurs can give problems */ 42786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cr[0] |= CR0_TS_MASK; 42886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags |= HF_TS_MASK; 42986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.selector = tss_selector; 43086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.base = tss_base; 43186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.limit = tss_limit; 43286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; 43386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 43486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { 43586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr3(env, new_cr3); 43686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 43786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 43886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* load all registers without an exception, then reload them with 43986797937017f52bff088d02edf64fb931177a7eaJun Nakajima possible exception */ 44086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = new_eip; 44186797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask = TF_MASK | AC_MASK | ID_MASK | 44286797937017f52bff088d02edf64fb931177a7eaJun Nakajima IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; 44386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(type & 8)) 44486797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask &= 0xffff; 44586797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(new_eflags, eflags_mask); 44686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: what to do in 16 bit case ? */ 44786797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = new_regs[0]; 44886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ECX = new_regs[1]; 44986797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = new_regs[2]; 45086797937017f52bff088d02edf64fb931177a7eaJun Nakajima EBX = new_regs[3]; 45186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = new_regs[4]; 45286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EBP = new_regs[5]; 45386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESI = new_regs[6]; 45486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDI = new_regs[7]; 45586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_eflags & VM_MASK) { 45686797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) 45786797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_vm(i, new_segs[i]); 45886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* in vm86, CPL is always 3 */ 45986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 3); 46086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 46186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* CPL is set the RPL of CS */ 46286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, new_segs[R_CS] & 3); 46386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* first just selectors as the rest may trigger exceptions */ 46486797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) 46586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); 46686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 46786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 46886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.selector = new_ldt & ~4; 46986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.base = 0; 47086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.limit = 0; 47186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.flags = 0; 47286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 47386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* load the LDT */ 47486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_ldt & 4) 47586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); 47686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 47786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((new_ldt & 0xfffc) != 0) { 47886797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->gdt; 47986797937017f52bff088d02edf64fb931177a7eaJun Nakajima index = new_ldt & ~7; 48086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((index + 7) > dt->limit) 48186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); 48286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + index; 48386797937017f52bff088d02edf64fb931177a7eaJun Nakajima e1 = ldl_kernel(ptr); 48486797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 48586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) 48686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); 48786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 48886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); 48986797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_cache_raw_dt(&env->ldt, e1, e2); 49086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 49186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 49286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* load the segments */ 49386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(new_eflags & VM_MASK)) { 49486797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_load_seg(R_CS, new_segs[R_CS]); 49586797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_load_seg(R_SS, new_segs[R_SS]); 49686797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_load_seg(R_ES, new_segs[R_ES]); 49786797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_load_seg(R_DS, new_segs[R_DS]); 49886797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_load_seg(R_FS, new_segs[R_FS]); 49986797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_load_seg(R_GS, new_segs[R_GS]); 50086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 50186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 50286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check that EIP is in the CS segment limits */ 50386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_eip > env->segs[R_CS].limit) { 50486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: different exception if CALL ? */ 50586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 50686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 50786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 50886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifndef CONFIG_USER_ONLY 50986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* reset local breakpoints */ 51086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->dr[7] & 0x55) { 51186797937017f52bff088d02edf64fb931177a7eaJun Nakajima for (i = 0; i < 4; i++) { 51286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) 51386797937017f52bff088d02edf64fb931177a7eaJun Nakajima hw_breakpoint_remove(env, i); 51486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 51586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[7] &= ~0x55; 51686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 51786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 51886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 51986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 52086797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* check if Port I/O is allowed in TSS */ 52186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void check_io(int addr, int size) 52286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 52386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int io_offset, val, mask; 52486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 52586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* TSS must be a valid 32 bit one */ 52686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->tr.flags & DESC_P_MASK) || 52786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || 52886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.limit < 103) 52986797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 53086797937017f52bff088d02edf64fb931177a7eaJun Nakajima io_offset = lduw_kernel(env->tr.base + 0x66); 53186797937017f52bff088d02edf64fb931177a7eaJun Nakajima io_offset += (addr >> 3); 53286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Note: the check needs two bytes */ 53386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((io_offset + 1) > env->tr.limit) 53486797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 53586797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = lduw_kernel(env->tr.base + io_offset); 53686797937017f52bff088d02edf64fb931177a7eaJun Nakajima val >>= (addr & 7); 53786797937017f52bff088d02edf64fb931177a7eaJun Nakajima mask = (1 << size) - 1; 53886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* all bits must be zero to allow the I/O */ 53986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((val & mask) != 0) { 54086797937017f52bff088d02edf64fb931177a7eaJun Nakajima fail: 54186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 54286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 54386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 54486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 54586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_check_iob(uint32_t t0) 54686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 54786797937017f52bff088d02edf64fb931177a7eaJun Nakajima check_io(t0, 1); 54886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 54986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 55086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_check_iow(uint32_t t0) 55186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 55286797937017f52bff088d02edf64fb931177a7eaJun Nakajima check_io(t0, 2); 55386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 55486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 55586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_check_iol(uint32_t t0) 55686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 55786797937017f52bff088d02edf64fb931177a7eaJun Nakajima check_io(t0, 4); 55886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 55986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 56086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_outb(uint32_t port, uint32_t data) 56186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 56286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_outb(port, data & 0xff); 56386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 56486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 56586797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_inb(uint32_t port) 56686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 56786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return cpu_inb(port); 56886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 56986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 57086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_outw(uint32_t port, uint32_t data) 57186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 57286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_outw(port, data & 0xffff); 57386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 57486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 57586797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_inw(uint32_t port) 57686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 57786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return cpu_inw(port); 57886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 57986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 58086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_outl(uint32_t port, uint32_t data) 58186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 58286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_outl(port, data); 58386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 58486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 58586797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_inl(uint32_t port) 58686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 58786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return cpu_inl(port); 58886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 58986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 59086797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline unsigned int get_sp_mask(unsigned int e2) 59186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 59286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_B_MASK) 59386797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0xffffffff; 59486797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 59586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0xffff; 59686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 59786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 59886797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int exeption_has_error_code(int intno) 59986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 60086797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(intno) { 60186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 8: 60286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 10: 60386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 11: 60486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 12: 60586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 13: 60686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 14: 60786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 17: 60886797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 1; 60986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 61086797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 61186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 61286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 61386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 61486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SET_ESP(val, sp_mask)\ 61586797937017f52bff088d02edf64fb931177a7eaJun Nakajimado {\ 61686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((sp_mask) == 0xffff)\ 61786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = (ESP & ~0xffff) | ((val) & 0xffff);\ 61886797937017f52bff088d02edf64fb931177a7eaJun Nakajima else if ((sp_mask) == 0xffffffffLL)\ 61986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = (uint32_t)(val);\ 62086797937017f52bff088d02edf64fb931177a7eaJun Nakajima else\ 62186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = (val);\ 62286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} while (0) 62386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 62486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask)) 62586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 62686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 62786797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* in 64-bit machines, this can overflow. So this segment addition macro 62886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * can be used to trim the value to 32-bit whenever needed */ 62986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask)))) 63086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 63186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: add a is_user flag to have proper security support */ 63286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define PUSHW(ssp, sp, sp_mask, val)\ 63386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{\ 63486797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp -= 2;\ 63586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel((ssp) + (sp & (sp_mask)), (val));\ 63686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 63786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 63886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define PUSHL(ssp, sp, sp_mask, val)\ 63986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{\ 64086797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp -= 4;\ 64186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\ 64286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 64386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 64486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define POPW(ssp, sp, sp_mask, val)\ 64586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{\ 64686797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = lduw_kernel((ssp) + (sp & (sp_mask)));\ 64786797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp += 2;\ 64886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 64986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 65086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define POPL(ssp, sp, sp_mask, val)\ 65186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{\ 65286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\ 65386797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp += 4;\ 65486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 65586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 65686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* protected mode interrupt */ 65786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void do_interrupt_protected(int intno, int is_int, int error_code, 65886797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int next_eip, int is_hw) 65986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 66086797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 66186797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr, ssp; 66286797937017f52bff088d02edf64fb931177a7eaJun Nakajima int type, dpl, selector, ss_dpl, cpl; 66386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int has_error_code, new_stack, shift; 66486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0; 66586797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t old_eip, sp_mask; 66686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 66786797937017f52bff088d02edf64fb931177a7eaJun Nakajima has_error_code = 0; 66886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!is_int && !is_hw) 66986797937017f52bff088d02edf64fb931177a7eaJun Nakajima has_error_code = exeption_has_error_code(intno); 67086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int) 67186797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eip = next_eip; 67286797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 67386797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eip = env->eip; 67486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 67586797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->idt; 67686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (intno * 8 + 7 > dt->limit) 67786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, intno * 8 + 2); 67886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + intno * 8; 67986797937017f52bff088d02edf64fb931177a7eaJun Nakajima e1 = ldl_kernel(ptr); 68086797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 68186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check gate type */ 68286797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; 68386797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(type) { 68486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 5: /* task gate */ 68586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* must do that check here to return the correct error code */ 68686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 68786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); 68886797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); 68986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (has_error_code) { 69086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int type; 69186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t mask; 69286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* push the error code */ 69386797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; 69486797937017f52bff088d02edf64fb931177a7eaJun Nakajima shift = type >> 3; 69586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->segs[R_SS].flags & DESC_B_MASK) 69686797937017f52bff088d02edf64fb931177a7eaJun Nakajima mask = 0xffffffff; 69786797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 69886797937017f52bff088d02edf64fb931177a7eaJun Nakajima mask = 0xffff; 69986797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = (ESP - (2 << shift)) & mask; 70086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base + esp; 70186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift) 70286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(ssp, error_code); 70386797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 70486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_kernel(ssp, error_code); 70586797937017f52bff088d02edf64fb931177a7eaJun Nakajima SET_ESP(esp, mask); 70686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 70786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 70886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 6: /* 286 interrupt gate */ 70986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 7: /* 286 trap gate */ 71086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 14: /* 386 interrupt gate */ 71186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 15: /* 386 trap gate */ 71286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 71386797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 71486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, intno * 8 + 2); 71586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 71686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 71786797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 71886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 71986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check privilege if software int */ 72086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int && dpl < cpl) 72186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, intno * 8 + 2); 72286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check valid bit */ 72386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 72486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); 72586797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = e1 >> 16; 72686797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); 72786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) 72886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 72986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 73086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 73186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 73286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) 73386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 73486797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 73586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl > cpl) 73686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 73786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 73886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 73986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_C_MASK) && dpl < cpl) { 74086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* to inner privilege */ 74186797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_ss_esp_from_tss(&ss, &esp, dpl); 74286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((ss & 0xfffc) == 0) 74386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 74486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((ss & 3) != dpl) 74586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 74686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&ss_e1, &ss_e2, ss) != 0) 74786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 74886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; 74986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ss_dpl != dpl) 75086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 75186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(ss_e2 & DESC_S_MASK) || 75286797937017f52bff088d02edf64fb931177a7eaJun Nakajima (ss_e2 & DESC_CS_MASK) || 75386797937017f52bff088d02edf64fb931177a7eaJun Nakajima !(ss_e2 & DESC_W_MASK)) 75486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 75586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(ss_e2 & DESC_P_MASK)) 75686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 75786797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 1; 75886797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = get_sp_mask(ss_e2); 75986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = get_seg_base(ss_e1, ss_e2); 76086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else if ((e2 & DESC_C_MASK) || dpl == cpl) { 76186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* to same privilege */ 76286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VM_MASK) 76386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 76486797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 0; 76586797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = get_sp_mask(env->segs[R_SS].flags); 76686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 76786797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = ESP; 76886797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = cpl; 76986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 77086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 77186797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 0; /* avoid warning */ 77286797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = 0; /* avoid warning */ 77386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = 0; /* avoid warning */ 77486797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = 0; /* avoid warning */ 77586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 77686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 77786797937017f52bff088d02edf64fb931177a7eaJun Nakajima shift = type >> 3; 77886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 77986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if 0 78086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: check that enough room is available */ 78186797937017f52bff088d02edf64fb931177a7eaJun Nakajima push_size = 6 + (new_stack << 2) + (has_error_code << 1); 78286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VM_MASK) 78386797937017f52bff088d02edf64fb931177a7eaJun Nakajima push_size += 8; 78486797937017f52bff088d02edf64fb931177a7eaJun Nakajima push_size <<= shift; 78586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 78686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 1) { 78786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_stack) { 78886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VM_MASK) { 78986797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); 79086797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); 79186797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); 79286797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); 79386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 79486797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); 79586797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, ESP); 79686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 79786797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, compute_eflags()); 79886797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); 79986797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, old_eip); 80086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (has_error_code) { 80186797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, sp_mask, error_code); 80286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 80386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 80486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_stack) { 80586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VM_MASK) { 80686797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); 80786797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); 80886797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); 80986797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); 81086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 81186797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); 81286797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, ESP); 81386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 81486797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, compute_eflags()); 81586797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); 81686797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, old_eip); 81786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (has_error_code) { 81886797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, sp_mask, error_code); 81986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 82086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 82186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 82286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_stack) { 82386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VM_MASK) { 82486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); 82586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0); 82686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0); 82786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); 82886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 82986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss = (ss & ~3) | dpl; 83086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, ss, 83186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); 83286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 83386797937017f52bff088d02edf64fb931177a7eaJun Nakajima SET_ESP(esp, sp_mask); 83486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 83586797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = (selector & ~3) | dpl; 83686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, selector, 83786797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 83886797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), 83986797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2); 84086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, dpl); 84186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = offset; 84286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 84386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* interrupt gate clear IF mask */ 84486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((type & 1) == 0) { 84586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~IF_MASK; 84686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 84786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); 84886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 84986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 85086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 85186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 85286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define PUSHQ(sp, val)\ 85386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{\ 85486797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp -= 8;\ 85586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_kernel(sp, (val));\ 85686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 85786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 85886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define POPQ(sp, val)\ 85986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{\ 86086797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = ldq_kernel(sp);\ 86186797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp += 8;\ 86286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 86386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 86486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline target_ulong get_rsp_from_tss(int level) 86586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 86686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int index; 86786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 86886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if 0 86986797937017f52bff088d02edf64fb931177a7eaJun Nakajima printf("TR: base=" TARGET_FMT_lx " limit=%x\n", 87086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.base, env->tr.limit); 87186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 87286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 87386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->tr.flags & DESC_P_MASK)) 87486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_abort(env, "invalid tss"); 87586797937017f52bff088d02edf64fb931177a7eaJun Nakajima index = 8 * level + 4; 87686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((index + 7) > env->tr.limit) 87786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); 87886797937017f52bff088d02edf64fb931177a7eaJun Nakajima return ldq_kernel(env->tr.base + index); 87986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 88086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 88186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 64 bit interrupt */ 88286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void do_interrupt64(int intno, int is_int, int error_code, 88386797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong next_eip, int is_hw) 88486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 88586797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 88686797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 88786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int type, dpl, selector, cpl, ist; 88886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int has_error_code, new_stack; 88986797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, e3, ss; 89086797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong old_eip, esp, offset; 89186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 89286797937017f52bff088d02edf64fb931177a7eaJun Nakajima has_error_code = 0; 89386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!is_int && !is_hw) 89486797937017f52bff088d02edf64fb931177a7eaJun Nakajima has_error_code = exeption_has_error_code(intno); 89586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int) 89686797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eip = next_eip; 89786797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 89886797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eip = env->eip; 89986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 90086797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->idt; 90186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (intno * 16 + 15 > dt->limit) 90286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, intno * 16 + 2); 90386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + intno * 16; 90486797937017f52bff088d02edf64fb931177a7eaJun Nakajima e1 = ldl_kernel(ptr); 90586797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 90686797937017f52bff088d02edf64fb931177a7eaJun Nakajima e3 = ldl_kernel(ptr + 8); 90786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check gate type */ 90886797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; 90986797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(type) { 91086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 14: /* 386 interrupt gate */ 91186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 15: /* 386 trap gate */ 91286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 91386797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 91486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, intno * 16 + 2); 91586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 91686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 91786797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 91886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 91986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check privilege if software int */ 92086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int && dpl < cpl) 92186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, intno * 16 + 2); 92286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check valid bit */ 92386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 92486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); 92586797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = e1 >> 16; 92686797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); 92786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ist = e2 & 7; 92886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) 92986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 93086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 93186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 93286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 93386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) 93486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 93586797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 93686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl > cpl) 93786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 93886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 93986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 94086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) 94186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 94286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { 94386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* to inner privilege */ 94486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ist != 0) 94586797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = get_rsp_from_tss(ist + 3); 94686797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 94786797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = get_rsp_from_tss(dpl); 94886797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp &= ~0xfLL; /* align stack */ 94986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss = 0; 95086797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 1; 95186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else if ((e2 & DESC_C_MASK) || dpl == cpl) { 95286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* to same privilege */ 95386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VM_MASK) 95486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 95586797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 0; 95686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ist != 0) 95786797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = get_rsp_from_tss(ist + 3); 95886797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 95986797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = ESP; 96086797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp &= ~0xfLL; /* align stack */ 96186797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = cpl; 96286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 96386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 96486797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 0; /* avoid warning */ 96586797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = 0; /* avoid warning */ 96686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 96786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 96886797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(esp, env->segs[R_SS].selector); 96986797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(esp, ESP); 97086797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(esp, compute_eflags()); 97186797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(esp, env->segs[R_CS].selector); 97286797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(esp, old_eip); 97386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (has_error_code) { 97486797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(esp, error_code); 97586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 97686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 97786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_stack) { 97886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss = 0 | dpl; 97986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); 98086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 98186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = esp; 98286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 98386797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = (selector & ~3) | dpl; 98486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, selector, 98586797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 98686797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), 98786797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2); 98886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, dpl); 98986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = offset; 99086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 99186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* interrupt gate clear IF mask */ 99286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((type & 1) == 0) { 99386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~IF_MASK; 99486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 99586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); 99686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 99786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 99886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 99986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 100086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(CONFIG_USER_ONLY) 100186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_syscall(int next_eip_addend) 100286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 100386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = EXCP_SYSCALL; 100486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_next_eip = env->eip + next_eip_addend; 100586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 100686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 100786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 100886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_syscall(int next_eip_addend) 100986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 101086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int selector; 101186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 101286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->efer & MSR_EFER_SCE)) { 101386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP06_ILLOP, 0); 101486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 101586797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = (env->star >> 32) & 0xffff; 101686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) { 101786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int code64; 101886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 101986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ECX = env->eip + next_eip_addend; 102086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->regs[11] = compute_eflags(); 102186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 102286797937017f52bff088d02edf64fb931177a7eaJun Nakajima code64 = env->hflags & HF_CS64_MASK; 102386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 102486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 0); 102586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 102686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 102786797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_P_MASK | 102886797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | 102986797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); 103086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 103186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 103286797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 103386797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | 103486797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 103586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~env->fmask; 103686797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(env->eflags, 0); 103786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (code64) 103886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = env->lstar; 103986797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 104086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = env->cstar; 104186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 104286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ECX = (uint32_t)(env->eip + next_eip_addend); 104386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 104486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 0); 104586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 104686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 104786797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 104886797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | 104986797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); 105086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 105186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 105286797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 105386797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | 105486797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 105586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); 105686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = (uint32_t)env->star; 105786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 105886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 105986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 106086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 106186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 106286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 106386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_sysret(int dflag) 106486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 106586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int cpl, selector; 106686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 106786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->efer & MSR_EFER_SCE)) { 106886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP06_ILLOP, 0); 106986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 107086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 107186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { 107286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 107386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 107486797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = (env->star >> 48) & 0xffff; 107586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) { 107686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dflag == 2) { 107786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 107886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 107986797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_P_MASK | 108086797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 108186797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | 108286797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_L_MASK); 108386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = ECX; 108486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 108586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, selector | 3, 108686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 108786797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 108886797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 108986797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); 109086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = (uint32_t)ECX; 109186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 109286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, selector + 8, 109386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 109486797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 109586797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 109686797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 109786797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | 109886797937017f52bff088d02edf64fb931177a7eaJun Nakajima IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); 109986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 3); 110086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 110186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, selector | 3, 110286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 110386797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 110486797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 110586797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); 110686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = (uint32_t)ECX; 110786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, selector + 8, 110886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 110986797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 111086797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 111186797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 111286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags |= IF_MASK; 111386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 3); 111486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 111586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef CONFIG_KQEMU 111686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (kqemu_is_ok(env)) { 111786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) 111886797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 111986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = -1; 112086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 112186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 112286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 112386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 112486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 112586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 112686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* real mode interrupt */ 112786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void do_interrupt_real(int intno, int is_int, int error_code, 112886797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int next_eip) 112986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 113086797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 113186797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr, ssp; 113286797937017f52bff088d02edf64fb931177a7eaJun Nakajima int selector; 113386797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t offset, esp; 113486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t old_cs, old_eip; 113586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 113686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* real mode (simpler !) */ 113786797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->idt; 113886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (intno * 4 + 3 > dt->limit) 113986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, intno * 8 + 2); 114086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + intno * 4; 114186797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = lduw_kernel(ptr); 114286797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = lduw_kernel(ptr + 2); 114386797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = ESP; 114486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 114586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int) 114686797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eip = next_eip; 114786797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 114886797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_eip = env->eip; 114986797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_cs = env->segs[R_CS].selector; 115086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: use SS segment size ? */ 115186797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, 0xffff, compute_eflags()); 115286797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, 0xffff, old_cs); 115386797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, 0xffff, old_eip); 115486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 115586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* update processor state */ 115686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = (ESP & ~0xffff) | (esp & 0xffff); 115786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = offset; 115886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_CS].selector = selector; 115986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_CS].base = (selector << 4); 116086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); 116186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 116286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 116386797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* fake user mode interrupt */ 116486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid do_interrupt_user(int intno, int is_int, int error_code, 116586797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong next_eip) 116686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 116786797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 116886797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 116986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int dpl, cpl, shift; 117086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e2; 117186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 117286797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->idt; 117386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) { 117486797937017f52bff088d02edf64fb931177a7eaJun Nakajima shift = 4; 117586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 117686797937017f52bff088d02edf64fb931177a7eaJun Nakajima shift = 3; 117786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 117886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + (intno << shift); 117986797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 118086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 118186797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 118286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 118386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check privilege if software int */ 118486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int && dpl < cpl) 118586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, (intno << shift) + 2); 118686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 118786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Since we emulate only user space, we cannot do more than 118886797937017f52bff088d02edf64fb931177a7eaJun Nakajima exiting the emulation with the suitable exception and error 118986797937017f52bff088d02edf64fb931177a7eaJun Nakajima code */ 119086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int) 119186797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = next_eip; 119286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 119386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 119486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 119586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void handle_even_inj(int intno, int is_int, int error_code, 119686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int is_hw, int rm) 119786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 119886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); 119986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(event_inj & SVM_EVTINJ_VALID)) { 120086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int type; 120186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_int) 120286797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = SVM_EVTINJ_TYPE_SOFT; 120386797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 120486797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = SVM_EVTINJ_TYPE_EXEPT; 120586797937017f52bff088d02edf64fb931177a7eaJun Nakajima event_inj = intno | type | SVM_EVTINJ_VALID; 120686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!rm && exeption_has_error_code(intno)) { 120786797937017f52bff088d02edf64fb931177a7eaJun Nakajima event_inj |= SVM_EVTINJ_VALID_ERR; 120886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code); 120986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 121086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj); 121186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 121286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 121386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 121486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 121586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 121686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Begin execution of an interruption. is_int is TRUE if coming from 121786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * the int instruction. next_eip is the EIP value AFTER the interrupt 121886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * instruction. It is only relevant if is_int is TRUE. 121986797937017f52bff088d02edf64fb931177a7eaJun Nakajima */ 122086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid do_interrupt(int intno, int is_int, int error_code, 122186797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong next_eip, int is_hw) 122286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 122386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (qemu_loglevel_mask(CPU_LOG_INT)) { 122486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((env->cr[0] & CR0_PE_MASK)) { 122586797937017f52bff088d02edf64fb931177a7eaJun Nakajima static int count; 122686797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, 122786797937017f52bff088d02edf64fb931177a7eaJun Nakajima count, intno, error_code, is_int, 122886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags & HF_CPL_MASK, 122986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_CS].selector, EIP, 123086797937017f52bff088d02edf64fb931177a7eaJun Nakajima (int)env->segs[R_CS].base + EIP, 123186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_SS].selector, ESP); 123286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (intno == 0x0e) { 123386797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]); 123486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 123586797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log(" EAX=" TARGET_FMT_lx, EAX); 123686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 123786797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log("\n"); 123886797937017f52bff088d02edf64fb931177a7eaJun Nakajima log_cpu_state(env, X86_DUMP_CCOP); 123986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if 0 124086797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 124186797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i; 124286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint8_t *ptr; 124386797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log(" code="); 124486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = env->segs[R_CS].base + env->eip; 124586797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 16; i++) { 124686797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log(" %02x", ldub(ptr + i)); 124786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 124886797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log("\n"); 124986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 125086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 125186797937017f52bff088d02edf64fb931177a7eaJun Nakajima count++; 125286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 125386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 125486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cr[0] & CR0_PE_MASK) { 125586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 125686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_SVMI_MASK) 125786797937017f52bff088d02edf64fb931177a7eaJun Nakajima handle_even_inj(intno, is_int, error_code, is_hw, 0); 125886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 125986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 126086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) { 126186797937017f52bff088d02edf64fb931177a7eaJun Nakajima do_interrupt64(intno, is_int, error_code, next_eip, is_hw); 126286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 126386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 126486797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 126586797937017f52bff088d02edf64fb931177a7eaJun Nakajima do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); 126686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 126786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 126886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 126986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_SVMI_MASK) 127086797937017f52bff088d02edf64fb931177a7eaJun Nakajima handle_even_inj(intno, is_int, error_code, is_hw, 1); 127186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 127286797937017f52bff088d02edf64fb931177a7eaJun Nakajima do_interrupt_real(intno, is_int, error_code, next_eip); 127386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 127486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 127586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 127686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_SVMI_MASK) { 127786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); 127886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID); 127986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 128086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 128186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 128286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 128386797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* This should come from sysemu.h - if we could include it here... */ 128486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid qemu_system_reset_request(void); 128586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 128686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 128786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Check nested exceptions and change to double or triple fault if 128886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * needed. It should only be called, if this is not an interrupt. 128986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Returns the new exception number. 129086797937017f52bff088d02edf64fb931177a7eaJun Nakajima */ 129186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int check_exception(int intno, int *error_code) 129286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 129386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int first_contributory = env->old_exception == 0 || 129486797937017f52bff088d02edf64fb931177a7eaJun Nakajima (env->old_exception >= 10 && 129586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->old_exception <= 13); 129686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int second_contributory = intno == 0 || 129786797937017f52bff088d02edf64fb931177a7eaJun Nakajima (intno >= 10 && intno <= 13); 129886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 129986797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n", 130086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->old_exception, intno); 130186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 130286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 130386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->old_exception == EXCP08_DBLE) { 130486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_SVMI_MASK) 130586797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */ 130686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 130786797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); 130886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 130986797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_system_reset_request(); 131086797937017f52bff088d02edf64fb931177a7eaJun Nakajima return EXCP_HLT; 131186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 131286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 131386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 131486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((first_contributory && second_contributory) 131586797937017f52bff088d02edf64fb931177a7eaJun Nakajima || (env->old_exception == EXCP0E_PAGE && 131686797937017f52bff088d02edf64fb931177a7eaJun Nakajima (second_contributory || (intno == EXCP0E_PAGE)))) { 131786797937017f52bff088d02edf64fb931177a7eaJun Nakajima intno = EXCP08_DBLE; 131886797937017f52bff088d02edf64fb931177a7eaJun Nakajima *error_code = 0; 131986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 132086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 132186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (second_contributory || (intno == EXCP0E_PAGE) || 132286797937017f52bff088d02edf64fb931177a7eaJun Nakajima (intno == EXCP08_DBLE)) 132386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->old_exception = intno; 132486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 132586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return intno; 132686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 132786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 132886797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 132986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Signal an interruption. It is executed in the main CPU loop. 133086797937017f52bff088d02edf64fb931177a7eaJun Nakajima * is_int is TRUE if coming from the int instruction. next_eip is the 133186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * EIP value AFTER the interrupt instruction. It is only relevant if 133286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * is_int is TRUE. 133386797937017f52bff088d02edf64fb931177a7eaJun Nakajima */ 133486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code, 133586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int next_eip_addend) 133686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 133786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!is_int) { 133886797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); 133986797937017f52bff088d02edf64fb931177a7eaJun Nakajima intno = check_exception(intno, &error_code); 134086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 134186797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0); 134286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 134386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 134486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = intno; 134586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->error_code = error_code; 134686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_is_int = is_int; 134786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_next_eip = env->eip + next_eip_addend; 134886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 134986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 135086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 135186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* shortcuts to generate exceptions */ 135286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 135386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid raise_exception_err(int exception_index, int error_code) 135486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 135586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_interrupt(exception_index, 0, error_code, 0); 135686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 135786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 135886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid raise_exception(int exception_index) 135986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 136086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_interrupt(exception_index, 0, 0, 0); 136186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 136286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 136386797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* SMM support */ 136486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 136586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(CONFIG_USER_ONLY) 136686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 136786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid do_smm_enter(void) 136886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 136986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 137086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 137186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_rsm(void) 137286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 137386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 137486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 137586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 137686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 137786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 137886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SMM_REVISION_ID 0x00020064 137986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 138086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SMM_REVISION_ID 0x00020000 138186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 138286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 138386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid do_smm_enter(void) 138486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 138586797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong sm_state; 138686797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 138786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i, offset; 138886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 138986797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_INT, "SMM: enter\n"); 139086797937017f52bff088d02edf64fb931177a7eaJun Nakajima log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); 139186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 139286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags |= HF_SMM_MASK; 139386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_smm_update(env); 139486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 139586797937017f52bff088d02edf64fb931177a7eaJun Nakajima sm_state = env->smbase + 0x8000; 139686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 139786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 139886797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) { 139986797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->segs[i]; 140086797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = 0x7e00 + i * 16; 140186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_phys(sm_state + offset, dt->selector); 140286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff); 140386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + offset + 4, dt->limit); 140486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + offset + 8, dt->base); 140586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 140686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 140786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7e68, env->gdt.base); 140886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7e64, env->gdt.limit); 140986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 141086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_phys(sm_state + 0x7e70, env->ldt.selector); 141186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7e78, env->ldt.base); 141286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7e74, env->ldt.limit); 141386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); 141486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 141586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7e88, env->idt.base); 141686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7e84, env->idt.limit); 141786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 141886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_phys(sm_state + 0x7e90, env->tr.selector); 141986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7e98, env->tr.base); 142086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7e94, env->tr.limit); 142186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); 142286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 142386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7ed0, env->efer); 142486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 142586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7ff8, EAX); 142686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7ff0, ECX); 142786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7fe8, EDX); 142886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7fe0, EBX); 142986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7fd8, ESP); 143086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7fd0, EBP); 143186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7fc8, ESI); 143286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7fc0, EDI); 143386797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 8; i < 16; i++) 143486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]); 143586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(sm_state + 0x7f78, env->eip); 143686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f70, compute_eflags()); 143786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f68, env->dr[6]); 143886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f60, env->dr[7]); 143986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 144086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f48, env->cr[4]); 144186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f50, env->cr[3]); 144286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f58, env->cr[0]); 144386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 144486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); 144586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f00, env->smbase); 144686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 144786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7ffc, env->cr[0]); 144886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7ff8, env->cr[3]); 144986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7ff4, compute_eflags()); 145086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7ff0, env->eip); 145186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fec, EDI); 145286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fe8, ESI); 145386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fe4, EBP); 145486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fe0, ESP); 145586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fdc, EBX); 145686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fd8, EDX); 145786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fd4, ECX); 145886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fd0, EAX); 145986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fcc, env->dr[6]); 146086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fc8, env->dr[7]); 146186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 146286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fc4, env->tr.selector); 146386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f64, env->tr.base); 146486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f60, env->tr.limit); 146586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); 146686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 146786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fc0, env->ldt.selector); 146886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f80, env->ldt.base); 146986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f7c, env->ldt.limit); 147086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); 147186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 147286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f74, env->gdt.base); 147386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f70, env->gdt.limit); 147486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 147586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f58, env->idt.base); 147686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f54, env->idt.limit); 147786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 147886797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) { 147986797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->segs[i]; 148086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (i < 3) 148186797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = 0x7f84 + i * 12; 148286797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 148386797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = 0x7f2c + (i - 3) * 12; 148486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector); 148586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + offset + 8, dt->base); 148686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + offset + 4, dt->limit); 148786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff); 148886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 148986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7f14, env->cr[4]); 149086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 149186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); 149286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(sm_state + 0x7ef8, env->smbase); 149386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 149486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* init SMM cpu state */ 149586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 149686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 149786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_load_efer(env, 0); 149886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 149986797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); 150086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = 0x00008000; 150186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, 150286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0xffffffff, 0); 150386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0); 150486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0); 150586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); 150686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); 150786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); 150886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 150986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr0(env, 151086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); 151186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr4(env, 0); 151286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[7] = 0x00000400; 151386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 151486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 151586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 151686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_rsm(void) 151786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 151886797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong sm_state; 151986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i, offset; 152086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t val; 152186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 152286797937017f52bff088d02edf64fb931177a7eaJun Nakajima sm_state = env->smbase + 0x8000; 152386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 152486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0)); 152586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 152686797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) { 152786797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = 0x7e00 + i * 16; 152886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, i, 152986797937017f52bff088d02edf64fb931177a7eaJun Nakajima lduw_phys(sm_state + offset), 153086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldq_phys(sm_state + offset + 8), 153186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldl_phys(sm_state + offset + 4), 153286797937017f52bff088d02edf64fb931177a7eaJun Nakajima (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8); 153386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 153486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 153586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.base = ldq_phys(sm_state + 0x7e68); 153686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.limit = ldl_phys(sm_state + 0x7e64); 153786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 153886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.selector = lduw_phys(sm_state + 0x7e70); 153986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.base = ldq_phys(sm_state + 0x7e78); 154086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.limit = ldl_phys(sm_state + 0x7e74); 154186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8; 154286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 154386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.base = ldq_phys(sm_state + 0x7e88); 154486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.limit = ldl_phys(sm_state + 0x7e84); 154586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 154686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.selector = lduw_phys(sm_state + 0x7e90); 154786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.base = ldq_phys(sm_state + 0x7e98); 154886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.limit = ldl_phys(sm_state + 0x7e94); 154986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; 155086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 155186797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = ldq_phys(sm_state + 0x7ff8); 155286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ECX = ldq_phys(sm_state + 0x7ff0); 155386797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = ldq_phys(sm_state + 0x7fe8); 155486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EBX = ldq_phys(sm_state + 0x7fe0); 155586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = ldq_phys(sm_state + 0x7fd8); 155686797937017f52bff088d02edf64fb931177a7eaJun Nakajima EBP = ldq_phys(sm_state + 0x7fd0); 155786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESI = ldq_phys(sm_state + 0x7fc8); 155886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDI = ldq_phys(sm_state + 0x7fc0); 155986797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 8; i < 16; i++) 156086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8); 156186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = ldq_phys(sm_state + 0x7f78); 156286797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(ldl_phys(sm_state + 0x7f70), 156386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); 156486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[6] = ldl_phys(sm_state + 0x7f68); 156586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[7] = ldl_phys(sm_state + 0x7f60); 156686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 156786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48)); 156886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50)); 156986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58)); 157086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 157186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = ldl_phys(sm_state + 0x7efc); /* revision ID */ 157286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (val & 0x20000) { 157386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff; 157486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 157586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 157686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc)); 157786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8)); 157886797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(ldl_phys(sm_state + 0x7ff4), 157986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); 158086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = ldl_phys(sm_state + 0x7ff0); 158186797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDI = ldl_phys(sm_state + 0x7fec); 158286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESI = ldl_phys(sm_state + 0x7fe8); 158386797937017f52bff088d02edf64fb931177a7eaJun Nakajima EBP = ldl_phys(sm_state + 0x7fe4); 158486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = ldl_phys(sm_state + 0x7fe0); 158586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EBX = ldl_phys(sm_state + 0x7fdc); 158686797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = ldl_phys(sm_state + 0x7fd8); 158786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ECX = ldl_phys(sm_state + 0x7fd4); 158886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = ldl_phys(sm_state + 0x7fd0); 158986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[6] = ldl_phys(sm_state + 0x7fcc); 159086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[7] = ldl_phys(sm_state + 0x7fc8); 159186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 159286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff; 159386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.base = ldl_phys(sm_state + 0x7f64); 159486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.limit = ldl_phys(sm_state + 0x7f60); 159586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8; 159686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 159786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff; 159886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.base = ldl_phys(sm_state + 0x7f80); 159986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.limit = ldl_phys(sm_state + 0x7f7c); 160086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8; 160186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 160286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.base = ldl_phys(sm_state + 0x7f74); 160386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.limit = ldl_phys(sm_state + 0x7f70); 160486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 160586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.base = ldl_phys(sm_state + 0x7f58); 160686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.limit = ldl_phys(sm_state + 0x7f54); 160786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 160886797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 6; i++) { 160986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (i < 3) 161086797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = 0x7f84 + i * 12; 161186797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 161286797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = 0x7f2c + (i - 3) * 12; 161386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, i, 161486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff, 161586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldl_phys(sm_state + offset + 8), 161686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldl_phys(sm_state + offset + 4), 161786797937017f52bff088d02edf64fb931177a7eaJun Nakajima (ldl_phys(sm_state + offset) & 0xf0ff) << 8); 161886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 161986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14)); 162086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 162186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = ldl_phys(sm_state + 0x7efc); /* revision ID */ 162286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (val & 0x20000) { 162386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff; 162486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 162586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 162686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 162786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags &= ~HF_SMM_MASK; 162886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_smm_update(env); 162986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 163086797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); 163186797937017f52bff088d02edf64fb931177a7eaJun Nakajima log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); 163286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 163386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 163486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif /* !CONFIG_USER_ONLY */ 163586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 163686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 163786797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* division, flags are undefined */ 163886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 163986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_divb_AL(target_ulong t0) 164086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 164186797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int num, den, q, r; 164286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 164386797937017f52bff088d02edf64fb931177a7eaJun Nakajima num = (EAX & 0xffff); 164486797937017f52bff088d02edf64fb931177a7eaJun Nakajima den = (t0 & 0xff); 164586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (den == 0) { 164686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 164786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 164886797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (num / den); 164986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (q > 0xff) 165086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 165186797937017f52bff088d02edf64fb931177a7eaJun Nakajima q &= 0xff; 165286797937017f52bff088d02edf64fb931177a7eaJun Nakajima r = (num % den) & 0xff; 165386797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | (r << 8) | q; 165486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 165586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 165686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_idivb_AL(target_ulong t0) 165786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 165886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int num, den, q, r; 165986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 166086797937017f52bff088d02edf64fb931177a7eaJun Nakajima num = (int16_t)EAX; 166186797937017f52bff088d02edf64fb931177a7eaJun Nakajima den = (int8_t)t0; 166286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (den == 0) { 166386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 166486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 166586797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (num / den); 166686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (q != (int8_t)q) 166786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 166886797937017f52bff088d02edf64fb931177a7eaJun Nakajima q &= 0xff; 166986797937017f52bff088d02edf64fb931177a7eaJun Nakajima r = (num % den) & 0xff; 167086797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | (r << 8) | q; 167186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 167286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 167386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_divw_AX(target_ulong t0) 167486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 167586797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int num, den, q, r; 167686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 167786797937017f52bff088d02edf64fb931177a7eaJun Nakajima num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); 167886797937017f52bff088d02edf64fb931177a7eaJun Nakajima den = (t0 & 0xffff); 167986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (den == 0) { 168086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 168186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 168286797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (num / den); 168386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (q > 0xffff) 168486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 168586797937017f52bff088d02edf64fb931177a7eaJun Nakajima q &= 0xffff; 168686797937017f52bff088d02edf64fb931177a7eaJun Nakajima r = (num % den) & 0xffff; 168786797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | q; 168886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = (EDX & ~0xffff) | r; 168986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 169086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 169186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_idivw_AX(target_ulong t0) 169286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 169386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int num, den, q, r; 169486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 169586797937017f52bff088d02edf64fb931177a7eaJun Nakajima num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); 169686797937017f52bff088d02edf64fb931177a7eaJun Nakajima den = (int16_t)t0; 169786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (den == 0) { 169886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 169986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 170086797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (num / den); 170186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (q != (int16_t)q) 170286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 170386797937017f52bff088d02edf64fb931177a7eaJun Nakajima q &= 0xffff; 170486797937017f52bff088d02edf64fb931177a7eaJun Nakajima r = (num % den) & 0xffff; 170586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | q; 170686797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = (EDX & ~0xffff) | r; 170786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 170886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 170986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_divl_EAX(target_ulong t0) 171086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 171186797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int den, r; 171286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t num, q; 171386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 171486797937017f52bff088d02edf64fb931177a7eaJun Nakajima num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); 171586797937017f52bff088d02edf64fb931177a7eaJun Nakajima den = t0; 171686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (den == 0) { 171786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 171886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 171986797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (num / den); 172086797937017f52bff088d02edf64fb931177a7eaJun Nakajima r = (num % den); 172186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (q > 0xffffffff) 172286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 172386797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (uint32_t)q; 172486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = (uint32_t)r; 172586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 172686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 172786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_idivl_EAX(target_ulong t0) 172886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 172986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int den, r; 173086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int64_t num, q; 173186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 173286797937017f52bff088d02edf64fb931177a7eaJun Nakajima num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); 173386797937017f52bff088d02edf64fb931177a7eaJun Nakajima den = t0; 173486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (den == 0) { 173586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 173686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 173786797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (num / den); 173886797937017f52bff088d02edf64fb931177a7eaJun Nakajima r = (num % den); 173986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (q != (int32_t)q) 174086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 174186797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (uint32_t)q; 174286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = (uint32_t)r; 174386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 174486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 174586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* bcd */ 174686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 174786797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: exception */ 174886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_aam(int base) 174986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 175086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int al, ah; 175186797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = EAX & 0xff; 175286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ah = al / base; 175386797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = al % base; 175486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | al | (ah << 8); 175586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_DST = al; 175686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 175786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 175886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_aad(int base) 175986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 176086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int al, ah; 176186797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = EAX & 0xff; 176286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ah = (EAX >> 8) & 0xff; 176386797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = ((ah * base) + al) & 0xff; 176486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | al; 176586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_DST = al; 176686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 176786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 176886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_aaa(void) 176986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 177086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int icarry; 177186797937017f52bff088d02edf64fb931177a7eaJun Nakajima int al, ah, af; 177286797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 177386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 177486797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 177586797937017f52bff088d02edf64fb931177a7eaJun Nakajima af = eflags & CC_A; 177686797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = EAX & 0xff; 177786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ah = (EAX >> 8) & 0xff; 177886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 177986797937017f52bff088d02edf64fb931177a7eaJun Nakajima icarry = (al > 0xf9); 178086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (((al & 0x0f) > 9 ) || af) { 178186797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = (al + 6) & 0x0f; 178286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ah = (ah + 1 + icarry) & 0xff; 178386797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_C | CC_A; 178486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 178586797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags &= ~(CC_C | CC_A); 178686797937017f52bff088d02edf64fb931177a7eaJun Nakajima al &= 0x0f; 178786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 178886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | al | (ah << 8); 178986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 179086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 179186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 179286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_aas(void) 179386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 179486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int icarry; 179586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int al, ah, af; 179686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 179786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 179886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 179986797937017f52bff088d02edf64fb931177a7eaJun Nakajima af = eflags & CC_A; 180086797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = EAX & 0xff; 180186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ah = (EAX >> 8) & 0xff; 180286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 180386797937017f52bff088d02edf64fb931177a7eaJun Nakajima icarry = (al < 6); 180486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (((al & 0x0f) > 9 ) || af) { 180586797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = (al - 6) & 0x0f; 180686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ah = (ah - 1 - icarry) & 0xff; 180786797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_C | CC_A; 180886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 180986797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags &= ~(CC_C | CC_A); 181086797937017f52bff088d02edf64fb931177a7eaJun Nakajima al &= 0x0f; 181186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 181286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xffff) | al | (ah << 8); 181386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 181486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 181586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 181686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_daa(void) 181786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 181886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int al, af, cf; 181986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 182086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 182186797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 182286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cf = eflags & CC_C; 182386797937017f52bff088d02edf64fb931177a7eaJun Nakajima af = eflags & CC_A; 182486797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = EAX & 0xff; 182586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 182686797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = 0; 182786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (((al & 0x0f) > 9 ) || af) { 182886797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = (al + 6) & 0xff; 182986797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_A; 183086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 183186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((al > 0x9f) || cf) { 183286797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = (al + 0x60) & 0xff; 183386797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_C; 183486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 183586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xff) | al; 183686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* well, speed is not an issue here, so we compute the flags by hand */ 183786797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= (al == 0) << 6; /* zf */ 183886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= parity_table[al]; /* pf */ 183986797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= (al & 0x80); /* sf */ 184086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 184186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 184286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 184386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_das(void) 184486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 184586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int al, al1, af, cf; 184686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 184786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 184886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 184986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cf = eflags & CC_C; 185086797937017f52bff088d02edf64fb931177a7eaJun Nakajima af = eflags & CC_A; 185186797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = EAX & 0xff; 185286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 185386797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = 0; 185486797937017f52bff088d02edf64fb931177a7eaJun Nakajima al1 = al; 185586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (((al & 0x0f) > 9 ) || af) { 185686797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_A; 185786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (al < 6 || cf) 185886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_C; 185986797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = (al - 6) & 0xff; 186086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 186186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((al1 > 0x99) || cf) { 186286797937017f52bff088d02edf64fb931177a7eaJun Nakajima al = (al - 0x60) & 0xff; 186386797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_C; 186486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 186586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (EAX & ~0xff) | al; 186686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* well, speed is not an issue here, so we compute the flags by hand */ 186786797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= (al == 0) << 6; /* zf */ 186886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= parity_table[al]; /* pf */ 186986797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= (al & 0x80); /* sf */ 187086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 187186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 187286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 187386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_into(int next_eip_addend) 187486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 187586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 187686797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 187786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (eflags & CC_O) { 187886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend); 187986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 188086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 188186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 188286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_cmpxchg8b(target_ulong a0) 188386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 188486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t d; 188586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 188686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 188786797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 188886797937017f52bff088d02edf64fb931177a7eaJun Nakajima d = ldq(a0); 188986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) { 189086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX); 189186797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_Z; 189286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 189386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* always do the store */ 1894f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stq(a0, d); 189586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = (uint32_t)(d >> 32); 189686797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (uint32_t)d; 189786797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags &= ~CC_Z; 189886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 189986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 190086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 190186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 190286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 190386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_cmpxchg16b(target_ulong a0) 190486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 190586797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t d0, d1; 190686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 190786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 190886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((a0 & 0xf) != 0) 190986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP0D_GPF); 191086797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 191186797937017f52bff088d02edf64fb931177a7eaJun Nakajima d0 = ldq(a0); 191286797937017f52bff088d02edf64fb931177a7eaJun Nakajima d1 = ldq(a0 + 8); 191386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (d0 == EAX && d1 == EDX) { 191486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(a0, EBX); 191586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(a0 + 8, ECX); 191686797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags |= CC_Z; 191786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 191886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* always do the store */ 1919f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stq(a0, d0); 1920f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stq(a0 + 8, d1); 192186797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = d1; 192286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = d0; 192386797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags &= ~CC_Z; 192486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 192586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 192686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 192786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 192886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 192986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_single_step(void) 193086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 193186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifndef CONFIG_USER_ONLY 193286797937017f52bff088d02edf64fb931177a7eaJun Nakajima check_hw_breakpoints(env, 1); 193386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[6] |= DR6_BS; 193486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 193586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP01_DB); 193686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 193786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 193886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_cpuid(void) 193986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 194086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t eax, ebx, ecx, edx; 194186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 194286797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0); 194386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 194486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx); 194586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = eax; 194686797937017f52bff088d02edf64fb931177a7eaJun Nakajima EBX = ebx; 194786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ECX = ecx; 194886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = edx; 194986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 195086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 195186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_enter_level(int level, int data32, target_ulong t1) 195286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 195386797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ssp; 195486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t esp_mask, esp, ebp; 195586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 195686797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp_mask = get_sp_mask(env->segs[R_SS].flags); 195786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 195886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ebp = EBP; 195986797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = ESP; 196086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (data32) { 196186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 32 bit */ 196286797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 4; 196386797937017f52bff088d02edf64fb931177a7eaJun Nakajima while (--level) { 196486797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 4; 196586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ebp -= 4; 196686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); 196786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 196886797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 4; 196986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ssp + (esp & esp_mask), t1); 197086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 197186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bit */ 197286797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 2; 197386797937017f52bff088d02edf64fb931177a7eaJun Nakajima while (--level) { 197486797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 2; 197586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ebp -= 2; 197686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); 197786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 197886797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 2; 197986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ssp + (esp & esp_mask), t1); 198086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 198186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 198286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 198386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 198486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_enter64_level(int level, int data64, target_ulong t1) 198586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 198686797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong esp, ebp; 198786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ebp = EBP; 198886797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = ESP; 198986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 199086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (data64) { 199186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 64 bit */ 199286797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 8; 199386797937017f52bff088d02edf64fb931177a7eaJun Nakajima while (--level) { 199486797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 8; 199586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ebp -= 8; 199686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(esp, ldq(ebp)); 199786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 199886797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 8; 199986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(esp, t1); 200086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 200186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bit */ 200286797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 2; 200386797937017f52bff088d02edf64fb931177a7eaJun Nakajima while (--level) { 200486797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 2; 200586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ebp -= 2; 200686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(esp, lduw(ebp)); 200786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 200886797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp -= 2; 200986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(esp, t1); 201086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 201186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 201286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 201386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 201486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_lldt(int selector) 201586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 201686797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 201786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2; 201886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int index, entry_limit; 201986797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 202086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 202186797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector &= 0xffff; 202286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) { 202386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: NULL selector case: invalid LDT */ 202486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.base = 0; 202586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.limit = 0; 202686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 202786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (selector & 0x4) 202886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 202986797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->gdt; 203086797937017f52bff088d02edf64fb931177a7eaJun Nakajima index = selector & ~7; 203186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 203286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) 203386797937017f52bff088d02edf64fb931177a7eaJun Nakajima entry_limit = 15; 203486797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 203586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 203686797937017f52bff088d02edf64fb931177a7eaJun Nakajima entry_limit = 7; 203786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((index + entry_limit) > dt->limit) 203886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 203986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + index; 204086797937017f52bff088d02edf64fb931177a7eaJun Nakajima e1 = ldl_kernel(ptr); 204186797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 204286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) 204386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 204486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 204586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 204686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 204786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) { 204886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e3; 204986797937017f52bff088d02edf64fb931177a7eaJun Nakajima e3 = ldl_kernel(ptr + 8); 205086797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_cache_raw_dt(&env->ldt, e1, e2); 205186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.base |= (target_ulong)e3 << 32; 205286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 205386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 205486797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 205586797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_cache_raw_dt(&env->ldt, e1, e2); 205686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 205786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 205886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->ldt.selector = selector; 205986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 206086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 206186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_ltr(int selector) 206286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 206386797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 206486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2; 206586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int index, type, entry_limit; 206686797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 206786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 206886797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector &= 0xffff; 206986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) { 207086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* NULL selector case: invalid TR */ 207186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.base = 0; 207286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.limit = 0; 207386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.flags = 0; 207486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 207586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (selector & 0x4) 207686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 207786797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->gdt; 207886797937017f52bff088d02edf64fb931177a7eaJun Nakajima index = selector & ~7; 207986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 208086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) 208186797937017f52bff088d02edf64fb931177a7eaJun Nakajima entry_limit = 15; 208286797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 208386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 208486797937017f52bff088d02edf64fb931177a7eaJun Nakajima entry_limit = 7; 208586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((index + entry_limit) > dt->limit) 208686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 208786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + index; 208886797937017f52bff088d02edf64fb931177a7eaJun Nakajima e1 = ldl_kernel(ptr); 208986797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 209086797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0xf; 209186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_S_MASK) || 209286797937017f52bff088d02edf64fb931177a7eaJun Nakajima (type != 1 && type != 9)) 209386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 209486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 209586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 209686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 209786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) { 209886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e3, e4; 209986797937017f52bff088d02edf64fb931177a7eaJun Nakajima e3 = ldl_kernel(ptr + 8); 210086797937017f52bff088d02edf64fb931177a7eaJun Nakajima e4 = ldl_kernel(ptr + 12); 210186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e4 >> DESC_TYPE_SHIFT) & 0xf) 210286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 210386797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_cache_raw_dt(&env->tr, e1, e2); 210486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.base |= (target_ulong)e3 << 32; 210586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 210686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 210786797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 210886797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_cache_raw_dt(&env->tr, e1, e2); 210986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 211086797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 |= DESC_TSS_BUSY_MASK; 211186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(ptr + 4, e2); 211286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 211386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tr.selector = selector; 211486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 211586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 211686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* only works if protected mode and not VM86. seg_reg must be != R_CS */ 211786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_load_seg(int seg_reg, int selector) 211886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 211986797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2; 212086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int cpl, dpl, rpl; 212186797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache *dt; 212286797937017f52bff088d02edf64fb931177a7eaJun Nakajima int index; 212386797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ptr; 212486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 212586797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector &= 0xffff; 212686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 212786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) { 212886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* null selector case */ 212986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (seg_reg == R_SS 213086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 213186797937017f52bff088d02edf64fb931177a7eaJun Nakajima && (!(env->hflags & HF_CS64_MASK) || cpl == 3) 213286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 213386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ) 213486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 213586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); 213686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 213786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 213886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (selector & 0x4) 213986797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->ldt; 214086797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 214186797937017f52bff088d02edf64fb931177a7eaJun Nakajima dt = &env->gdt; 214286797937017f52bff088d02edf64fb931177a7eaJun Nakajima index = selector & ~7; 214386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((index + 7) > dt->limit) 214486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 214586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr = dt->base + index; 214686797937017f52bff088d02edf64fb931177a7eaJun Nakajima e1 = ldl_kernel(ptr); 214786797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = ldl_kernel(ptr + 4); 214886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 214986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK)) 215086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 215186797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = selector & 3; 215286797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 215386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (seg_reg == R_SS) { 215486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* must be writable segment */ 215586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) 215686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 215786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (rpl != cpl || dpl != cpl) 215886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 215986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 216086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* must be readable segment */ 216186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) 216286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 216386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 216486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { 216586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* if not conforming code, test rights */ 216686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 216786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 216886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 216986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 217086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 217186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) { 217286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (seg_reg == R_SS) 217386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0C_STACK, selector & 0xfffc); 217486797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 217586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 217686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 217786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 217886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* set the access bit if not already set */ 217986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_A_MASK)) { 218086797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 |= DESC_A_MASK; 218186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_kernel(ptr + 4, e2); 218286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 218386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 218486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, seg_reg, selector, 218586797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 218686797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), 218786797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2); 218886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if 0 218986797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 219086797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector, (unsigned long)sc->base, sc->limit, sc->flags); 219186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 219286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 219386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 219486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 219586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* protected mode jump */ 219686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_ljmp_protected(int new_cs, target_ulong new_eip, 219786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int next_eip_addend) 219886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 219986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int gate_cs, type; 220086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, cpl, dpl, rpl, limit; 220186797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong next_eip; 220286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 220386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((new_cs & 0xfffc) == 0) 220486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 220586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, new_cs) != 0) 220686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 220786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 220886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_S_MASK) { 220986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_CS_MASK)) 221086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 221186797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 221286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_C_MASK) { 221386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* conforming code segment */ 221486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl > cpl) 221586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 221686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 221786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* non conforming code segment */ 221886797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = new_cs & 3; 221986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (rpl > cpl) 222086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 222186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl != cpl) 222286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 222386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 222486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 222586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); 222686797937017f52bff088d02edf64fb931177a7eaJun Nakajima limit = get_seg_limit(e1, e2); 222786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_eip > limit && 222886797937017f52bff088d02edf64fb931177a7eaJun Nakajima !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) 222986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 223086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, 223186797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), limit, e2); 223286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = new_eip; 223386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 223486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* jump to call or task gate */ 223586797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 223686797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = new_cs & 3; 223786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 223886797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0xf; 223986797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(type) { 224086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 1: /* 286 TSS */ 224186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 9: /* 386 TSS */ 224286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 5: /* task gate */ 224386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 224486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 224586797937017f52bff088d02edf64fb931177a7eaJun Nakajima next_eip = env->eip + next_eip_addend; 224686797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); 224786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 224886797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 224986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 4: /* 286 call gate */ 225086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 12: /* 386 call gate */ 225186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((dpl < cpl) || (dpl < rpl)) 225286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 225386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 225486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); 225586797937017f52bff088d02edf64fb931177a7eaJun Nakajima gate_cs = e1 >> 16; 225686797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eip = (e1 & 0xffff); 225786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type == 12) 225886797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eip |= (e2 & 0xffff0000); 225986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, gate_cs) != 0) 226086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); 226186797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 226286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* must be code segment */ 226386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != 226486797937017f52bff088d02edf64fb931177a7eaJun Nakajima (DESC_S_MASK | DESC_CS_MASK))) 226586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); 226686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (((e2 & DESC_C_MASK) && (dpl > cpl)) || 226786797937017f52bff088d02edf64fb931177a7eaJun Nakajima (!(e2 & DESC_C_MASK) && (dpl != cpl))) 226886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); 226986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 227086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); 227186797937017f52bff088d02edf64fb931177a7eaJun Nakajima limit = get_seg_limit(e1, e2); 227286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_eip > limit) 227386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 227486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, 227586797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), limit, e2); 227686797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = new_eip; 227786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 227886797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 227986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 228086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 228186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 228286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 228386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 228486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 228586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* real mode call */ 228686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_lcall_real(int new_cs, target_ulong new_eip1, 228786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int shift, int next_eip) 228886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 228986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int new_eip; 229086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t esp, esp_mask; 229186797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ssp; 229286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 229386797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eip = new_eip1; 229486797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp = ESP; 229586797937017f52bff088d02edf64fb931177a7eaJun Nakajima esp_mask = get_sp_mask(env->segs[R_SS].flags); 229686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 229786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift) { 229886797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); 229986797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, esp, esp_mask, next_eip); 230086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 230186797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); 230286797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, esp, esp_mask, next_eip); 230386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 230486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 230586797937017f52bff088d02edf64fb931177a7eaJun Nakajima SET_ESP(esp, esp_mask); 230686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = new_eip; 230786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_CS].selector = new_cs; 230886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_CS].base = (new_cs << 4); 230986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 231086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 231186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* protected mode call */ 2312f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turnervoid helper_lcall_protected(int new_cs, target_ulong new_eip, 231386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int shift, int next_eip_addend) 231486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 231586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int new_stack, i; 231686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; 231786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask; 231886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t val, limit, old_sp_mask; 231986797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ssp, old_ssp, next_eip; 232086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 232186797937017f52bff088d02edf64fb931177a7eaJun Nakajima next_eip = env->eip + next_eip_addend; 232286797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift); 232386797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL_STATE(env); 232486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((new_cs & 0xfffc) == 0) 232586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 232686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, new_cs) != 0) 232786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 232886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 232986797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL("desc=%08x:%08x\n", e1, e2); 233086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_S_MASK) { 233186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_CS_MASK)) 233286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 233386797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 233486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_C_MASK) { 233586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* conforming code segment */ 233686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl > cpl) 233786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 233886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 233986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* non conforming code segment */ 234086797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = new_cs & 3; 234186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (rpl > cpl) 234286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 234386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl != cpl) 234486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 234586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 234686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 234786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); 234886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 234986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 235086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: check 16/32 bit cases in long mode */ 235186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 2) { 235286797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong rsp; 235386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 64 bit case */ 235486797937017f52bff088d02edf64fb931177a7eaJun Nakajima rsp = ESP; 235586797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(rsp, env->segs[R_CS].selector); 235686797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHQ(rsp, next_eip); 235786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* from this point, not restartable */ 235886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = rsp; 235986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, 236086797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 236186797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), e2); 236286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = new_eip; 236386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 236486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 236586797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 236686797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp = ESP; 236786797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = get_sp_mask(env->segs[R_SS].flags); 236886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 236986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift) { 237086797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); 237186797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, sp, sp_mask, next_eip); 237286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 237386797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); 237486797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, sp, sp_mask, next_eip); 237586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 237686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 237786797937017f52bff088d02edf64fb931177a7eaJun Nakajima limit = get_seg_limit(e1, e2); 237886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_eip > limit) 237986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 238086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* from this point, not restartable */ 238186797937017f52bff088d02edf64fb931177a7eaJun Nakajima SET_ESP(sp, sp_mask); 238286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, 238386797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), limit, e2); 238486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = new_eip; 238586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 238686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 238786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check gate type */ 238886797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; 238986797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 239086797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = new_cs & 3; 239186797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(type) { 239286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 1: /* available 286 TSS */ 239386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 9: /* available 386 TSS */ 239486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 5: /* task gate */ 239586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 239686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 239786797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); 239886797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 239986797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 240086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 4: /* 286 call gate */ 240186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 12: /* 386 call gate */ 240286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 240386797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 240486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 240586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 240686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 240786797937017f52bff088d02edf64fb931177a7eaJun Nakajima shift = type >> 3; 240886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 240986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 241086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 241186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* check valid bit */ 241286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 241386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); 241486797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = e1 >> 16; 241586797937017f52bff088d02edf64fb931177a7eaJun Nakajima offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); 241686797937017f52bff088d02edf64fb931177a7eaJun Nakajima param_count = e2 & 0x1f; 241786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) 241886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 241986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 242086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 242186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 242286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) 242386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 242486797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 242586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl > cpl) 242686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 242786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 242886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 242986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 243086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_C_MASK) && dpl < cpl) { 243186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* to inner privilege */ 243286797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_ss_esp_from_tss(&ss, &sp, dpl); 243386797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", 243486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss, sp, param_count, ESP); 243586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((ss & 0xfffc) == 0) 243686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 243786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((ss & 3) != dpl) 243886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 243986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&ss_e1, &ss_e2, ss) != 0) 244086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 244186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; 244286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ss_dpl != dpl) 244386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 244486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(ss_e2 & DESC_S_MASK) || 244586797937017f52bff088d02edf64fb931177a7eaJun Nakajima (ss_e2 & DESC_CS_MASK) || 244686797937017f52bff088d02edf64fb931177a7eaJun Nakajima !(ss_e2 & DESC_W_MASK)) 244786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 244886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(ss_e2 & DESC_P_MASK)) 244986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, ss & 0xfffc); 245086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 245186797937017f52bff088d02edf64fb931177a7eaJun Nakajima // push_size = ((param_count * 2) + 8) << shift; 245286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 245386797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_sp_mask = get_sp_mask(env->segs[R_SS].flags); 245486797937017f52bff088d02edf64fb931177a7eaJun Nakajima old_ssp = env->segs[R_SS].base; 245586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 245686797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = get_sp_mask(ss_e2); 245786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = get_seg_base(ss_e1, ss_e2); 245886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift) { 245986797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); 246086797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, sp, sp_mask, ESP); 246186797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = param_count - 1; i >= 0; i--) { 246286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask)); 246386797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, sp, sp_mask, val); 246486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 246586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 246686797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); 246786797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, sp, sp_mask, ESP); 246886797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = param_count - 1; i >= 0; i--) { 246986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask)); 247086797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, sp, sp_mask, val); 247186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 247286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 247386797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 1; 247486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 247586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* to same privilege */ 247686797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp = ESP; 247786797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = get_sp_mask(env->segs[R_SS].flags); 247886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 247986797937017f52bff088d02edf64fb931177a7eaJun Nakajima // push_size = (4 << shift); 248086797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_stack = 0; 248186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 248286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 248386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift) { 248486797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); 248586797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHL(ssp, sp, sp_mask, next_eip); 248686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 248786797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); 248886797937017f52bff088d02edf64fb931177a7eaJun Nakajima PUSHW(ssp, sp, sp_mask, next_eip); 248986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 249086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 249186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* from this point, not restartable */ 249286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 249386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_stack) { 249486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss = (ss & ~3) | dpl; 249586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, ss, 249686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp, 249786797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(ss_e1, ss_e2), 249886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss_e2); 249986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 250086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 250186797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = (selector & ~3) | dpl; 250286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, selector, 250386797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 250486797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), 250586797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2); 250686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, dpl); 250786797937017f52bff088d02edf64fb931177a7eaJun Nakajima SET_ESP(sp, sp_mask); 250886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = offset; 250986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 251086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef CONFIG_KQEMU 251186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (kqemu_is_ok(env)) { 251286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = -1; 251386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 251486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 251586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 251686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 251786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 251886797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* real and vm86 mode iret */ 251986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_iret_real(int shift) 252086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 252186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; 252286797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ssp; 252386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags_mask; 252486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 252586797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = 0xffff; /* XXXX: use SS segment size ? */ 252686797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp = ESP; 252786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 252886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 1) { 252986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 32 bits */ 253086797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_eip); 253186797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_cs); 253286797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_cs &= 0xffff; 253386797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_eflags); 253486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 253586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bits */ 253686797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_eip); 253786797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_cs); 253886797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_eflags); 253986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 254086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = (ESP & ~sp_mask) | (sp & sp_mask); 254186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_CS].selector = new_cs; 254286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_CS].base = (new_cs << 4); 254386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = new_eip; 254486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VM_MASK) 254586797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK; 254686797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 254786797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK; 254886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 0) 254986797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask &= 0xffff; 255086797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(new_eflags, eflags_mask); 255186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 &= ~HF2_NMI_MASK; 255286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 255386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 255486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void validate_seg(int seg_reg, int cpl) 255586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 255686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int dpl; 255786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e2; 255886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 255986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: on x86_64, we do not want to nullify FS and GS because 256086797937017f52bff088d02edf64fb931177a7eaJun Nakajima they may still contain a valid base. I would be interested to 256186797937017f52bff088d02edf64fb931177a7eaJun Nakajima know how a real x86_64 CPU behaves */ 256286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((seg_reg == R_FS || seg_reg == R_GS) && 256386797937017f52bff088d02edf64fb931177a7eaJun Nakajima (env->segs[seg_reg].selector & 0xfffc) == 0) 256486797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 256586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 256686797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2 = env->segs[seg_reg].flags; 256786797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 256886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { 256986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* data or non conforming code segment */ 257086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl) { 257186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0); 257286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 257386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 257486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 257586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 257686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* protected mode iret */ 257786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void helper_ret_protected(int shift, int is_iret, int addend) 257886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 257986797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t new_cs, new_eflags, new_ss; 258086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t new_es, new_ds, new_fs, new_gs; 258186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, ss_e1, ss_e2; 258286797937017f52bff088d02edf64fb931177a7eaJun Nakajima int cpl, dpl, rpl, eflags_mask, iopl; 258386797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong ssp, sp, new_eip, new_esp, sp_mask; 258486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 258586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 258686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 2) 258786797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = -1; 258886797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 258986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 259086797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = get_sp_mask(env->segs[R_SS].flags); 259186797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp = ESP; 259286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ssp = env->segs[R_SS].base; 259386797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_eflags = 0; /* avoid warning */ 259486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 259586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 2) { 259686797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPQ(sp, new_eip); 259786797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPQ(sp, new_cs); 259886797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_cs &= 0xffff; 259986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_iret) { 260086797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPQ(sp, new_eflags); 260186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 260286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 260386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 260486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 1) { 260586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 32 bits */ 260686797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_eip); 260786797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_cs); 260886797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_cs &= 0xffff; 260986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_iret) { 261086797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_eflags); 261186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (new_eflags & VM_MASK) 261286797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto return_to_vm86; 261386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 261486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 261586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bits */ 261686797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_eip); 261786797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_cs); 261886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_iret) 261986797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_eflags); 262086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 262186797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n", 262286797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_cs, new_eip, shift, addend); 262386797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL_STATE(env); 262486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((new_cs & 0xfffc) == 0) 262586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 262686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, new_cs) != 0) 262786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 262886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK) || 262986797937017f52bff088d02edf64fb931177a7eaJun Nakajima !(e2 & DESC_CS_MASK)) 263086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 263186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 263286797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = new_cs & 3; 263386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (rpl < cpl) 263486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 263586797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 263686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_C_MASK) { 263786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl > rpl) 263886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 263986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 264086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl != rpl) 264186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 264286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 264386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_P_MASK)) 264486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); 264586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 264686797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp += addend; 264786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || 264886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ((env->hflags & HF_CS64_MASK) && !is_iret))) { 264986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* return to same privilege level */ 265086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, new_cs, 265186797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 265286797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), 265386797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2); 265486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 265586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* return to different privilege level */ 265686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 265786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 2) { 265886797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPQ(sp, new_esp); 265986797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPQ(sp, new_ss); 266086797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_ss &= 0xffff; 266186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 266286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 266386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 1) { 266486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 32 bits */ 266586797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_esp); 266686797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_ss); 266786797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_ss &= 0xffff; 266886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 266986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bits */ 267086797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_esp); 267186797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPW(ssp, sp, sp_mask, new_ss); 267286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 267386797937017f52bff088d02edf64fb931177a7eaJun Nakajima LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n", 267486797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_ss, new_esp); 267586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((new_ss & 0xfffc) == 0) { 267686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 267786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* NULL ss is allowed in long mode if cpl != 3*/ 267886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: test CS64 ? */ 267986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((env->hflags & HF_LMA_MASK) && rpl != 3) { 268086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, new_ss, 268186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 268286797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 268386797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | 268486797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 268586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */ 268686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 268786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 268886797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 268986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 269086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 269186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 269286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((new_ss & 3) != rpl) 269386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); 269486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) 269586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); 269686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(ss_e2 & DESC_S_MASK) || 269786797937017f52bff088d02edf64fb931177a7eaJun Nakajima (ss_e2 & DESC_CS_MASK) || 269886797937017f52bff088d02edf64fb931177a7eaJun Nakajima !(ss_e2 & DESC_W_MASK)) 269986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); 270086797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; 270186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl != rpl) 270286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); 270386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(ss_e2 & DESC_P_MASK)) 270486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); 270586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, new_ss, 270686797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(ss_e1, ss_e2), 270786797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(ss_e1, ss_e2), 270886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ss_e2); 270986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 271086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 271186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, new_cs, 271286797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_base(e1, e2), 271386797937017f52bff088d02edf64fb931177a7eaJun Nakajima get_seg_limit(e1, e2), 271486797937017f52bff088d02edf64fb931177a7eaJun Nakajima e2); 271586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, rpl); 271686797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp = new_esp; 271786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 271886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_CS64_MASK) 271986797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = -1; 272086797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 272186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 272286797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp_mask = get_sp_mask(ss_e2); 272386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 272486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* validate data segments */ 272586797937017f52bff088d02edf64fb931177a7eaJun Nakajima validate_seg(R_ES, rpl); 272686797937017f52bff088d02edf64fb931177a7eaJun Nakajima validate_seg(R_DS, rpl); 272786797937017f52bff088d02edf64fb931177a7eaJun Nakajima validate_seg(R_FS, rpl); 272886797937017f52bff088d02edf64fb931177a7eaJun Nakajima validate_seg(R_GS, rpl); 272986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 273086797937017f52bff088d02edf64fb931177a7eaJun Nakajima sp += addend; 273186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 273286797937017f52bff088d02edf64fb931177a7eaJun Nakajima SET_ESP(sp, sp_mask); 273386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = new_eip; 273486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (is_iret) { 273586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* NOTE: 'cpl' is the _old_ CPL */ 273686797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK; 273786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (cpl == 0) 273886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask |= IOPL_MASK; 273986797937017f52bff088d02edf64fb931177a7eaJun Nakajima iopl = (env->eflags >> IOPL_SHIFT) & 3; 274086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (cpl <= iopl) 274186797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask |= IF_MASK; 274286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (shift == 0) 274386797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags_mask &= 0xffff; 274486797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(new_eflags, eflags_mask); 274586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 274686797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 274786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 274886797937017f52bff088d02edf64fb931177a7eaJun Nakajima return_to_vm86: 274986797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_esp); 275086797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_ss); 275186797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_es); 275286797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_ds); 275386797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_fs); 275486797937017f52bff088d02edf64fb931177a7eaJun Nakajima POPL(ssp, sp, sp_mask, new_gs); 275586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 275686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* modify processor state */ 275786797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 275886797937017f52bff088d02edf64fb931177a7eaJun Nakajima IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); 275986797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_vm(R_CS, new_cs & 0xffff); 276086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 3); 276186797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_vm(R_SS, new_ss & 0xffff); 276286797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_vm(R_ES, new_es & 0xffff); 276386797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_vm(R_DS, new_ds & 0xffff); 276486797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_vm(R_FS, new_fs & 0xffff); 276586797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_seg_vm(R_GS, new_gs & 0xffff); 276686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 276786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = new_eip & 0xffff; 276886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = new_esp; 276986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 277086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 277186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_iret_protected(int shift, int next_eip) 277286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 277386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int tss_selector, type; 277486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2; 277586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 277686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* specific case for TSS */ 277786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & NT_MASK) { 277886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 277986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) 278086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 278186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 278286797937017f52bff088d02edf64fb931177a7eaJun Nakajima tss_selector = lduw_kernel(env->tr.base + 0); 278386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (tss_selector & 4) 278486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); 278586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, tss_selector) != 0) 278686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); 278786797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0x17; 278886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* NOTE: we check both segment and busy TSS */ 278986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type != 3) 279086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); 279186797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip); 279286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 279386797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_ret_protected(shift, 1, 0); 279486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 279586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 &= ~HF2_NMI_MASK; 279686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef CONFIG_KQEMU 279786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (kqemu_is_ok(env)) { 279886797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 279986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = -1; 280086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 280186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 280286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 280386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 280486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 280586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_lret_protected(int shift, int addend) 280686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 280786797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_ret_protected(shift, 0, addend); 280886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef CONFIG_KQEMU 280986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (kqemu_is_ok(env)) { 281086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = -1; 281186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 281286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 281386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 281486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 281586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 281686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_sysenter(void) 281786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 281886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->sysenter_cs == 0) { 281986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 282086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 282186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); 282286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 0); 282386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 282486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 282586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_LMA_MASK) { 282686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, 282786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 282886797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 282986797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | 283086797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); 283186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 283286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 283386797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 283486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, 283586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 283686797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 283786797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | 283886797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); 283986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 284086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, 284186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 284286797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 284386797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | 284486797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 284586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = env->sysenter_esp; 284686797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = env->sysenter_eip; 284786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 284886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 284986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_sysexit(int dflag) 285086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 285186797937017f52bff088d02edf64fb931177a7eaJun Nakajima int cpl; 285286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 285386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 285486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->sysenter_cs == 0 || cpl != 0) { 285586797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP0D_GPF, 0); 285686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 285786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 3); 285886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 285986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dflag == 2) { 286086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3, 286186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 286286797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 286386797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 286486797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); 286586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3, 286686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 286786797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 286886797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 286986797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 287086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 287186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 287286797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 287386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, 287486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 287586797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 287686797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 287786797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); 287886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, 287986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 0, 0xffffffff, 288086797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | 288186797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_S_MASK | (3 << DESC_DPL_SHIFT) | 288286797937017f52bff088d02edf64fb931177a7eaJun Nakajima DESC_W_MASK | DESC_A_MASK); 288386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 288486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = ECX; 288586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = EDX; 288686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef CONFIG_KQEMU 288786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (kqemu_is_ok(env)) { 288886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = -1; 288986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 289086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 289186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 289286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 289386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 289486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(CONFIG_USER_ONLY) 289586797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_read_crN(int reg) 289686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 289786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 289886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 289986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 290086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_write_crN(int reg, target_ulong t0) 290186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 290286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 290386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 290486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_movl_drN_T0(int reg, target_ulong t0) 290586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 290686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 290786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 290886797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_read_crN(int reg) 290986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 291086797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong val; 291186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 291286797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0); 291386797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(reg) { 291486797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 291586797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->cr[reg]; 291686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 291786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 8: 291886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->hflags2 & HF2_VINTR_MASK)) { 291986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = cpu_get_apic_tpr(env); 292086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 292186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->v_tpr; 292286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 292386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 292486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 292586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return val; 292686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 292786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 292886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_write_crN(int reg, target_ulong t0) 292986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 293086797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0); 293186797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(reg) { 293286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 0: 293386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr0(env, t0); 293486797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 293586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 3: 293686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr3(env, t0); 293786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 293886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 4: 293986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr4(env, t0); 294086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 294186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 8: 294286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->hflags2 & HF2_VINTR_MASK)) { 294386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_set_apic_tpr(env, t0); 294486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 294586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->v_tpr = t0 & 0x0f; 294686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 294786797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 294886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cr[reg] = t0; 294986797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 295086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 295186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 295286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 295386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_movl_drN_T0(int reg, target_ulong t0) 295486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 295586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i; 295686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 295786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (reg < 4) { 295886797937017f52bff088d02edf64fb931177a7eaJun Nakajima hw_breakpoint_remove(env, reg); 295986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[reg] = t0; 296086797937017f52bff088d02edf64fb931177a7eaJun Nakajima hw_breakpoint_insert(env, reg); 296186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else if (reg == 7) { 296286797937017f52bff088d02edf64fb931177a7eaJun Nakajima for (i = 0; i < 4; i++) 296386797937017f52bff088d02edf64fb931177a7eaJun Nakajima hw_breakpoint_remove(env, i); 296486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[7] = t0; 296586797937017f52bff088d02edf64fb931177a7eaJun Nakajima for (i = 0; i < 4; i++) 296686797937017f52bff088d02edf64fb931177a7eaJun Nakajima hw_breakpoint_insert(env, i); 296786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else 296886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[reg] = t0; 296986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 297086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 297186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 297286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_lmsw(target_ulong t0) 297386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 297486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* only 4 lower bits of CR0 are modified. PE cannot be set to zero 297586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if already set to one. */ 297686797937017f52bff088d02edf64fb931177a7eaJun Nakajima t0 = (env->cr[0] & ~0xe) | (t0 & 0xf); 297786797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_write_crN(0, t0); 297886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 297986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 298086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_clts(void) 298186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 298286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cr[0] &= ~CR0_TS_MASK; 298386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags &= ~HF_TS_MASK; 298486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 298586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 298686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_invlpg(target_ulong addr) 298786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 298886797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0); 298986797937017f52bff088d02edf64fb931177a7eaJun Nakajima tlb_flush_page(env, addr); 299086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 299186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 299286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_rdtsc(void) 299386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 299486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t val; 299586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 299686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { 299786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP0D_GPF); 299886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 299986797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0); 300086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 300186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = cpu_get_tsc(env) + env->tsc_offset; 300286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (uint32_t)(val); 300386797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = (uint32_t)(val >> 32); 300486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 300586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 300686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_rdpmc(void) 300786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 300886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { 300986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP0D_GPF); 301086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 301186797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0); 3012f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner 301386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* currently unimplemented */ 301486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(EXCP06_ILLOP, 0); 301586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 301686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 301786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(CONFIG_USER_ONLY) 301886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_wrmsr(void) 301986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 302086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 302186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 302286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_rdmsr(void) 302386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 302486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 302586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 302686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_wrmsr(void) 302786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 302886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t val; 302986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 303086797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_MSR, 1); 303186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 303286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); 303386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 303486797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch((uint32_t)ECX) { 303586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_SYSENTER_CS: 303686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->sysenter_cs = val & 0xffff; 303786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 303886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_SYSENTER_ESP: 303986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->sysenter_esp = val; 304086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 304186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_SYSENTER_EIP: 304286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->sysenter_eip = val; 304386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 304486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_APICBASE: 304586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_set_apic_base(env, val); 304686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 304786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_EFER: 304886797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 304986797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t update_mask; 305086797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_mask = 0; 305186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) 305286797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_mask |= MSR_EFER_SCE; 305386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpuid_ext2_features & CPUID_EXT2_LM) 305486797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_mask |= MSR_EFER_LME; 305586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) 305686797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_mask |= MSR_EFER_FFXSR; 305786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpuid_ext2_features & CPUID_EXT2_NX) 305886797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_mask |= MSR_EFER_NXE; 305986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpuid_ext3_features & CPUID_EXT3_SVM) 306086797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_mask |= MSR_EFER_SVME; 306186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) 306286797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_mask |= MSR_EFER_FFXSR; 306386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_load_efer(env, (env->efer & ~update_mask) | 306486797937017f52bff088d02edf64fb931177a7eaJun Nakajima (val & update_mask)); 306586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 306686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 306786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_STAR: 306886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->star = val; 306986797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 307086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_PAT: 307186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->pat = val; 307286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 307386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_VM_HSAVE_PA: 307486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->vm_hsave = val; 307586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 307686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 307786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_LSTAR: 307886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->lstar = val; 307986797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 308086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_CSTAR: 308186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cstar = val; 308286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 308386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_FMASK: 308486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fmask = val; 308586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 308686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_FSBASE: 308786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_FS].base = val; 308886797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 308986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_GSBASE: 309086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_GS].base = val; 309186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 309286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_KERNELGSBASE: 309386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->kernelgsbase = val; 309486797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 309586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 309686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(0): 309786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(1): 309886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(2): 309986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(3): 310086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(4): 310186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(5): 310286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(6): 310386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(7): 310486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val; 310586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 310686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(0): 310786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(1): 310886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(2): 310986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(3): 311086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(4): 311186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(5): 311286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(6): 311386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(7): 311486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val; 311586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 311686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix64K_00000: 311786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val; 311886797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 311986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix16K_80000: 312086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix16K_A0000: 312186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val; 312286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 312386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_C0000: 312486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_C8000: 312586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_D0000: 312686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_D8000: 312786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_E0000: 312886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_E8000: 312986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_F0000: 313086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_F8000: 313186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val; 313286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 313386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRdefType: 313486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mtrr_deftype = val; 313586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 313686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MCG_STATUS: 313786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mcg_status = val; 313886797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 313986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MCG_CTL: 314086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((env->mcg_cap & MCG_CTL_P) 314186797937017f52bff088d02edf64fb931177a7eaJun Nakajima && (val == 0 || val == ~(uint64_t)0)) 314286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mcg_ctl = val; 314386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 314486797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 314586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((uint32_t)ECX >= MSR_MC0_CTL 314686797937017f52bff088d02edf64fb931177a7eaJun Nakajima && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) { 314786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL; 314886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((offset & 0x3) != 0 314986797937017f52bff088d02edf64fb931177a7eaJun Nakajima || (val == 0 || val == ~(uint64_t)0)) 315086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mce_banks[offset] = val; 315186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 315286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 315386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: exception ? */ 315486797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 315586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 315686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 315786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 315886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_rdmsr(void) 315986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 316086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t val; 316186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 316286797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_MSR, 0); 316386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 316486797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch((uint32_t)ECX) { 316586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_SYSENTER_CS: 316686797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->sysenter_cs; 316786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 316886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_SYSENTER_ESP: 316986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->sysenter_esp; 317086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 317186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_SYSENTER_EIP: 317286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->sysenter_eip; 317386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 317486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_APICBASE: 317586797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = cpu_get_apic_base(env); 317686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 317786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_EFER: 317886797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->efer; 317986797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 318086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_STAR: 318186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->star; 318286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 318386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_PAT: 318486797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->pat; 318586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 318686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_VM_HSAVE_PA: 318786797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->vm_hsave; 318886797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 318986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_IA32_PERF_STATUS: 319086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* tsc_increment_by_tick */ 319186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = 1000ULL; 319286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* CPU multiplier */ 319386797937017f52bff088d02edf64fb931177a7eaJun Nakajima val |= (((uint64_t)4ULL) << 40); 319486797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 319586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 319686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_LSTAR: 319786797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->lstar; 319886797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 319986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_CSTAR: 320086797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->cstar; 320186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 320286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_FMASK: 320386797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->fmask; 320486797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 320586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_FSBASE: 320686797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->segs[R_FS].base; 320786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 320886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_GSBASE: 320986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->segs[R_GS].base; 321086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 321186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_KERNELGSBASE: 321286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->kernelgsbase; 321386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 321486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 321586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef CONFIG_KQEMU 321686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_QPI_COMMBASE: 321786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->kqemu_enabled) { 321886797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = kqemu_comm_base; 321986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 322086797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = 0; 322186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 322286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 322386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 322486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(0): 322586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(1): 322686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(2): 322786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(3): 322886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(4): 322986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(5): 323086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(6): 323186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysBase(7): 323286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base; 323386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 323486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(0): 323586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(1): 323686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(2): 323786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(3): 323886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(4): 323986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(5): 324086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(6): 324186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRphysMask(7): 324286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask; 324386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 324486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix64K_00000: 324586797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mtrr_fixed[0]; 324686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 324786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix16K_80000: 324886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix16K_A0000: 324986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1]; 325086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 325186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_C0000: 325286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_C8000: 325386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_D0000: 325486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_D8000: 325586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_E0000: 325686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_E8000: 325786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_F0000: 325886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRfix4K_F8000: 325986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3]; 326086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 326186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRdefType: 326286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mtrr_deftype; 326386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 326486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MTRRcap: 326586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpuid_features & CPUID_MTRR) 326686797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED; 326786797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 326886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: exception ? */ 326986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = 0; 327086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 327186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MCG_CAP: 327286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mcg_cap; 327386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 327486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MCG_CTL: 327586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->mcg_cap & MCG_CTL_P) 327686797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mcg_ctl; 327786797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 327886797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = 0; 327986797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 328086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case MSR_MCG_STATUS: 328186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mcg_status; 328286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 328386797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 328486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((uint32_t)ECX >= MSR_MC0_CTL 328586797937017f52bff088d02edf64fb931177a7eaJun Nakajima && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) { 328686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL; 328786797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = env->mce_banks[offset]; 328886797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 328986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 329086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: exception ? */ 329186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = 0; 329286797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 329386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 329486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = (uint32_t)(val); 329586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = (uint32_t)(val >> 32); 329686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 329786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 329886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 329986797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_lsl(target_ulong selector1) 330086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 330186797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int limit; 330286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, eflags, selector; 330386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int rpl, dpl, cpl, type; 330486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 330586797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = selector1 & 0xffff; 330686797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 330786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) 330886797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 330986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 331086797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 331186797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = selector & 3; 331286797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 331386797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 331486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_S_MASK) { 331586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { 331686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* conforming */ 331786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 331886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 331986797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 332086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 332186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 332286797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0xf; 332386797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(type) { 332486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 1: 332586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 2: 332686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 3: 332786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 9: 332886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 11: 332986797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 333086797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 333186797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 333286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 333386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) { 333486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fail: 333586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags & ~CC_Z; 333686797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 333786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 333886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 333986797937017f52bff088d02edf64fb931177a7eaJun Nakajima limit = get_seg_limit(e1, e2); 334086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags | CC_Z; 334186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return limit; 334286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 334386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 334486797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_lar(target_ulong selector1) 334586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 334686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, eflags, selector; 334786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int rpl, dpl, cpl, type; 334886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 334986797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = selector1 & 0xffff; 335086797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 335186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) 335286797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 335386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 335486797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 335586797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = selector & 3; 335686797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 335786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 335886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_S_MASK) { 335986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { 336086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* conforming */ 336186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 336286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 336386797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 336486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 336586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 336686797937017f52bff088d02edf64fb931177a7eaJun Nakajima type = (e2 >> DESC_TYPE_SHIFT) & 0xf; 336786797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(type) { 336886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 1: 336986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 2: 337086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 3: 337186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 4: 337286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 5: 337386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 9: 337486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 11: 337586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 12: 337686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 337786797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 337886797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 337986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 338086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) { 338186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fail: 338286797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags & ~CC_Z; 338386797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 338486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 338586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 338686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags | CC_Z; 338786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return e2 & 0x00f0ff00; 338886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 338986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 339086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_verr(target_ulong selector1) 339186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 339286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, eflags, selector; 339386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int rpl, dpl, cpl; 339486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 339586797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = selector1 & 0xffff; 339686797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 339786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) 339886797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 339986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 340086797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 340186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK)) 340286797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 340386797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = selector & 3; 340486797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 340586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 340686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_CS_MASK) { 340786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_R_MASK)) 340886797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 340986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_C_MASK)) { 341086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 341186797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 341286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 341386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 341486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) { 341586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fail: 341686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags & ~CC_Z; 341786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 341886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 341986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 342086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags | CC_Z; 342186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 342286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 342386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_verw(target_ulong selector1) 342486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 342586797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t e1, e2, eflags, selector; 342686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int rpl, dpl, cpl; 342786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 342886797937017f52bff088d02edf64fb931177a7eaJun Nakajima selector = selector1 & 0xffff; 342986797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 343086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((selector & 0xfffc) == 0) 343186797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 343286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_segment(&e1, &e2, selector) != 0) 343386797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 343486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_S_MASK)) 343586797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 343686797937017f52bff088d02edf64fb931177a7eaJun Nakajima rpl = selector & 3; 343786797937017f52bff088d02edf64fb931177a7eaJun Nakajima dpl = (e2 >> DESC_DPL_SHIFT) & 3; 343886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpl = env->hflags & HF_CPL_MASK; 343986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (e2 & DESC_CS_MASK) { 344086797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 344186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 344286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dpl < cpl || dpl < rpl) 344386797937017f52bff088d02edf64fb931177a7eaJun Nakajima goto fail; 344486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(e2 & DESC_W_MASK)) { 344586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fail: 344686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags & ~CC_Z; 344786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 344886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 344986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 345086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags | CC_Z; 345186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 345286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 345386797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* x87 FPU helpers */ 345486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 345586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void fpu_set_exception(int mask) 345686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 345786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= mask; 345886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->fpus & (~env->fpuc & FPUC_EM)) 345986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= FPUS_SE | FPUS_B; 346086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 346186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 346286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) 346386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 346486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (b == 0.0) 346586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpu_set_exception(FPUS_ZE); 346686797937017f52bff088d02edf64fb931177a7eaJun Nakajima return a / b; 346786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 346886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 346986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void fpu_raise_exception(void) 347086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 347186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cr[0] & CR0_NE_MASK) { 347286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP10_COPR); 347386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 347486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 347586797937017f52bff088d02edf64fb931177a7eaJun Nakajima else { 347686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_set_ferr(env); 347786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 347886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 347986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 348086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 348186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_flds_FT0(uint32_t val) 348286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 348386797937017f52bff088d02edf64fb931177a7eaJun Nakajima union { 348486797937017f52bff088d02edf64fb931177a7eaJun Nakajima float32 f; 348586797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t i; 348686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } u; 348786797937017f52bff088d02edf64fb931177a7eaJun Nakajima u.i = val; 348886797937017f52bff088d02edf64fb931177a7eaJun Nakajima FT0 = float32_to_floatx(u.f, &env->fp_status); 348986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 349086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 349186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldl_FT0(uint64_t val) 349286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 349386797937017f52bff088d02edf64fb931177a7eaJun Nakajima union { 349486797937017f52bff088d02edf64fb931177a7eaJun Nakajima float64 f; 349586797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t i; 349686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } u; 349786797937017f52bff088d02edf64fb931177a7eaJun Nakajima u.i = val; 349886797937017f52bff088d02edf64fb931177a7eaJun Nakajima FT0 = float64_to_floatx(u.f, &env->fp_status); 349986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 350086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 350186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fildl_FT0(int32_t val) 350286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 350386797937017f52bff088d02edf64fb931177a7eaJun Nakajima FT0 = int32_to_floatx(val, &env->fp_status); 350486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 350586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 350686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_flds_ST0(uint32_t val) 350786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 350886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int new_fpstt; 350986797937017f52bff088d02edf64fb931177a7eaJun Nakajima union { 351086797937017f52bff088d02edf64fb931177a7eaJun Nakajima float32 f; 351186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t i; 351286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } u; 351386797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_fpstt = (env->fpstt - 1) & 7; 351486797937017f52bff088d02edf64fb931177a7eaJun Nakajima u.i = val; 351586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status); 351686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = new_fpstt; 351786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[new_fpstt] = 0; /* validate stack entry */ 351886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 351986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 352086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldl_ST0(uint64_t val) 352186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 352286797937017f52bff088d02edf64fb931177a7eaJun Nakajima int new_fpstt; 352386797937017f52bff088d02edf64fb931177a7eaJun Nakajima union { 352486797937017f52bff088d02edf64fb931177a7eaJun Nakajima float64 f; 352586797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t i; 352686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } u; 352786797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_fpstt = (env->fpstt - 1) & 7; 352886797937017f52bff088d02edf64fb931177a7eaJun Nakajima u.i = val; 352986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status); 353086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = new_fpstt; 353186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[new_fpstt] = 0; /* validate stack entry */ 353286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 353386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 353486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fildl_ST0(int32_t val) 353586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 353686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int new_fpstt; 353786797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_fpstt = (env->fpstt - 1) & 7; 353886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status); 353986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = new_fpstt; 354086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[new_fpstt] = 0; /* validate stack entry */ 354186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 354286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 354386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fildll_ST0(int64_t val) 354486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 354586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int new_fpstt; 354686797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_fpstt = (env->fpstt - 1) & 7; 354786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status); 354886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = new_fpstt; 354986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[new_fpstt] = 0; /* validate stack entry */ 355086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 355186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 355286797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint32_t helper_fsts_ST0(void) 355386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 355486797937017f52bff088d02edf64fb931177a7eaJun Nakajima union { 355586797937017f52bff088d02edf64fb931177a7eaJun Nakajima float32 f; 355686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t i; 355786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } u; 355886797937017f52bff088d02edf64fb931177a7eaJun Nakajima u.f = floatx_to_float32(ST0, &env->fp_status); 355986797937017f52bff088d02edf64fb931177a7eaJun Nakajima return u.i; 356086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 356186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 356286797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint64_t helper_fstl_ST0(void) 356386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 356486797937017f52bff088d02edf64fb931177a7eaJun Nakajima union { 356586797937017f52bff088d02edf64fb931177a7eaJun Nakajima float64 f; 356686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t i; 356786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } u; 356886797937017f52bff088d02edf64fb931177a7eaJun Nakajima u.f = floatx_to_float64(ST0, &env->fp_status); 356986797937017f52bff088d02edf64fb931177a7eaJun Nakajima return u.i; 357086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 357186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 357286797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint32_t helper_fist_ST0(void) 357386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 357486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int32_t val; 357586797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = floatx_to_int32(ST0, &env->fp_status); 357686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (val != (int16_t)val) 357786797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = -32768; 357886797937017f52bff088d02edf64fb931177a7eaJun Nakajima return val; 357986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 358086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 358186797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint32_t helper_fistl_ST0(void) 358286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 358386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int32_t val; 358486797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = floatx_to_int32(ST0, &env->fp_status); 358586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return val; 358686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 358786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 358886797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint64_t helper_fistll_ST0(void) 358986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 359086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int64_t val; 359186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = floatx_to_int64(ST0, &env->fp_status); 359286797937017f52bff088d02edf64fb931177a7eaJun Nakajima return val; 359386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 359486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 359586797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint32_t helper_fistt_ST0(void) 359686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 359786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int32_t val; 359886797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = floatx_to_int32_round_to_zero(ST0, &env->fp_status); 359986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (val != (int16_t)val) 360086797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = -32768; 360186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return val; 360286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 360386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 360486797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint32_t helper_fisttl_ST0(void) 360586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 360686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int32_t val; 360786797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = floatx_to_int32_round_to_zero(ST0, &env->fp_status); 360886797937017f52bff088d02edf64fb931177a7eaJun Nakajima return val; 360986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 361086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 361186797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint64_t helper_fisttll_ST0(void) 361286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 361386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int64_t val; 361486797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = floatx_to_int64_round_to_zero(ST0, &env->fp_status); 361586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return val; 361686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 361786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 361886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldt_ST0(target_ulong ptr) 361986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 362086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int new_fpstt; 362186797937017f52bff088d02edf64fb931177a7eaJun Nakajima new_fpstt = (env->fpstt - 1) & 7; 362286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpregs[new_fpstt].d = helper_fldt(ptr); 362386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = new_fpstt; 362486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[new_fpstt] = 0; /* validate stack entry */ 362586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 362686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 362786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fstt_ST0(target_ulong ptr) 362886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 362986797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_fstt(ST0, ptr); 363086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 363186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 363286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fpush(void) 363386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 363486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpush(); 363586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 363686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 363786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fpop(void) 363886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 363986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpop(); 364086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 364186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 364286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fdecstp(void) 364386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 364486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = (env->fpstt - 1) & 7; 364586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); 364686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 364786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 364886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fincstp(void) 364986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 365086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = (env->fpstt + 1) & 7; 365186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); 365286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 365386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 365486797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* FPU move */ 365586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 365686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_ffree_STN(int st_index) 365786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 365886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[(env->fpstt + st_index) & 7] = 1; 365986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 366086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 366186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fmov_ST0_FT0(void) 366286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 366386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = FT0; 366486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 366586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 366686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fmov_FT0_STN(int st_index) 366786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 366886797937017f52bff088d02edf64fb931177a7eaJun Nakajima FT0 = ST(st_index); 366986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 367086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 367186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fmov_ST0_STN(int st_index) 367286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 367386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = ST(st_index); 367486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 367586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 367686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fmov_STN_ST0(int st_index) 367786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 367886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST(st_index) = ST0; 367986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 368086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 368186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fxchg_ST0_STN(int st_index) 368286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 368386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble tmp; 368486797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp = ST(st_index); 368586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST(st_index) = ST0; 368686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = tmp; 368786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 368886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 368986797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* FPU operations */ 369086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 369186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500}; 369286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 369386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fcom_ST0_FT0(void) 369486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 369586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int ret; 369686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 369786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ret = floatx_compare(ST0, FT0, &env->fp_status); 369886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; 369986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 370086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 370186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fucom_ST0_FT0(void) 370286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 370386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int ret; 370486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 370586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); 370686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1]; 370786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 370886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 370986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; 371086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 371186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fcomi_ST0_FT0(void) 371286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 371386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 371486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int ret; 371586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 371686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ret = floatx_compare(ST0, FT0, &env->fp_status); 371786797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 371886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; 371986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 372086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 372186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 372286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fucomi_ST0_FT0(void) 372386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 372486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int eflags; 372586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int ret; 372686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 372786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); 372886797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = helper_cc_compute_all(CC_OP); 372986797937017f52bff088d02edf64fb931177a7eaJun Nakajima eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; 373086797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = eflags; 373186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 373286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 373386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fadd_ST0_FT0(void) 373486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 373586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 += FT0; 373686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 373786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 373886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fmul_ST0_FT0(void) 373986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 374086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 *= FT0; 374186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 374286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 374386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsub_ST0_FT0(void) 374486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 374586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 -= FT0; 374686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 374786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 374886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsubr_ST0_FT0(void) 374986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 375086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = FT0 - ST0; 375186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 375286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 375386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fdiv_ST0_FT0(void) 375486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 375586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = helper_fdiv(ST0, FT0); 375686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 375786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 375886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fdivr_ST0_FT0(void) 375986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 376086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = helper_fdiv(FT0, ST0); 376186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 376286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 376386797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* fp operations between STN and ST0 */ 376486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 376586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fadd_STN_ST0(int st_index) 376686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 376786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST(st_index) += ST0; 376886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 376986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 377086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fmul_STN_ST0(int st_index) 377186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 377286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST(st_index) *= ST0; 377386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 377486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 377586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsub_STN_ST0(int st_index) 377686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 377786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST(st_index) -= ST0; 377886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 377986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 378086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsubr_STN_ST0(int st_index) 378186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 378286797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble *p; 378386797937017f52bff088d02edf64fb931177a7eaJun Nakajima p = &ST(st_index); 378486797937017f52bff088d02edf64fb931177a7eaJun Nakajima *p = ST0 - *p; 378586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 378686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 378786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fdiv_STN_ST0(int st_index) 378886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 378986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble *p; 379086797937017f52bff088d02edf64fb931177a7eaJun Nakajima p = &ST(st_index); 379186797937017f52bff088d02edf64fb931177a7eaJun Nakajima *p = helper_fdiv(*p, ST0); 379286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 379386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 379486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fdivr_STN_ST0(int st_index) 379586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 379686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble *p; 379786797937017f52bff088d02edf64fb931177a7eaJun Nakajima p = &ST(st_index); 379886797937017f52bff088d02edf64fb931177a7eaJun Nakajima *p = helper_fdiv(ST0, *p); 379986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 380086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 380186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* misc FPU operations */ 380286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fchs_ST0(void) 380386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 380486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = floatx_chs(ST0); 380586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 380686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 380786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fabs_ST0(void) 380886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 380986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = floatx_abs(ST0); 381086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 381186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 381286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fld1_ST0(void) 381386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 381486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = f15rk[1]; 381586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 381686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 381786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldl2t_ST0(void) 381886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 381986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = f15rk[6]; 382086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 382186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 382286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldl2e_ST0(void) 382386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 382486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = f15rk[5]; 382586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 382686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 382786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldpi_ST0(void) 382886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 382986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = f15rk[2]; 383086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 383186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 383286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldlg2_ST0(void) 383386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 383486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = f15rk[3]; 383586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 383686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 383786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldln2_ST0(void) 383886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 383986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = f15rk[4]; 384086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 384186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 384286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldz_ST0(void) 384386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 384486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = f15rk[0]; 384586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 384686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 384786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldz_FT0(void) 384886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 384986797937017f52bff088d02edf64fb931177a7eaJun Nakajima FT0 = f15rk[0]; 385086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 385186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 385286797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint32_t helper_fnstsw(void) 385386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 385486797937017f52bff088d02edf64fb931177a7eaJun Nakajima return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; 385586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 385686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 385786797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint32_t helper_fnstcw(void) 385886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 385986797937017f52bff088d02edf64fb931177a7eaJun Nakajima return env->fpuc; 386086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 386186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 386286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void update_fp_status(void) 386386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 386486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int rnd_type; 386586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 386686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* set rounding mode */ 386786797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(env->fpuc & RC_MASK) { 386886797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 386986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case RC_NEAR: 387086797937017f52bff088d02edf64fb931177a7eaJun Nakajima rnd_type = float_round_nearest_even; 387186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 387286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case RC_DOWN: 387386797937017f52bff088d02edf64fb931177a7eaJun Nakajima rnd_type = float_round_down; 387486797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 387586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case RC_UP: 387686797937017f52bff088d02edf64fb931177a7eaJun Nakajima rnd_type = float_round_up; 387786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 387886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case RC_CHOP: 387986797937017f52bff088d02edf64fb931177a7eaJun Nakajima rnd_type = float_round_to_zero; 388086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 388186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 388286797937017f52bff088d02edf64fb931177a7eaJun Nakajima set_float_rounding_mode(rnd_type, &env->fp_status); 388386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef FLOATX80 388486797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch((env->fpuc >> 8) & 3) { 388586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 0: 388686797937017f52bff088d02edf64fb931177a7eaJun Nakajima rnd_type = 32; 388786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 388886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 2: 388986797937017f52bff088d02edf64fb931177a7eaJun Nakajima rnd_type = 64; 389086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 389186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 3: 389286797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 389386797937017f52bff088d02edf64fb931177a7eaJun Nakajima rnd_type = 80; 389486797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 389586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 389686797937017f52bff088d02edf64fb931177a7eaJun Nakajima set_floatx80_rounding_precision(rnd_type, &env->fp_status); 389786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 389886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 389986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 390086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldcw(uint32_t val) 390186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 390286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpuc = val; 390386797937017f52bff088d02edf64fb931177a7eaJun Nakajima update_fp_status(); 390486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 390586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 390686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fclex(void) 390786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 390886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= 0x7f00; 390986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 391086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 391186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fwait(void) 391286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 391386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->fpus & FPUS_SE) 391486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpu_raise_exception(); 391586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 391686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 391786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fninit(void) 391886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 391986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus = 0; 392086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = 0; 392186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpuc = 0x37f; 392286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[0] = 1; 392386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[1] = 1; 392486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[2] = 1; 392586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[3] = 1; 392686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[4] = 1; 392786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[5] = 1; 392886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[6] = 1; 392986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[7] = 1; 393086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 393186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 393286797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* BCD ops */ 393386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 393486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fbld_ST0(target_ulong ptr) 393586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 393686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble tmp; 393786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t val; 393886797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int v; 393986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i; 394086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 394186797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = 0; 394286797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 8; i >= 0; i--) { 394386797937017f52bff088d02edf64fb931177a7eaJun Nakajima v = ldub(ptr + i); 394486797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); 394586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 394686797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp = val; 394786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ldub(ptr + 9) & 0x80) 394886797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp = -tmp; 394986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpush(); 395086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = tmp; 395186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 395286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 395386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fbst_ST0(target_ulong ptr) 395486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 395586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int v; 395686797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong mem_ref, mem_end; 395786797937017f52bff088d02edf64fb931177a7eaJun Nakajima int64_t val; 395886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 395986797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = floatx_to_int64(ST0, &env->fp_status); 396086797937017f52bff088d02edf64fb931177a7eaJun Nakajima mem_ref = ptr; 396186797937017f52bff088d02edf64fb931177a7eaJun Nakajima mem_end = mem_ref + 9; 396286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (val < 0) { 396386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stb(mem_end, 0x80); 396486797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = -val; 396586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 396686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stb(mem_end, 0x00); 396786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 396886797937017f52bff088d02edf64fb931177a7eaJun Nakajima while (mem_ref < mem_end) { 396986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (val == 0) 397086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 397186797937017f52bff088d02edf64fb931177a7eaJun Nakajima v = val % 100; 397286797937017f52bff088d02edf64fb931177a7eaJun Nakajima val = val / 100; 397386797937017f52bff088d02edf64fb931177a7eaJun Nakajima v = ((v / 10) << 4) | (v % 10); 397486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stb(mem_ref++, v); 397586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 397686797937017f52bff088d02edf64fb931177a7eaJun Nakajima while (mem_ref < mem_end) { 397786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stb(mem_ref++, 0); 397886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 397986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 398086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 398186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_f2xm1(void) 398286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 398386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = pow(2.0,ST0) - 1.0; 398486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 398586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 398686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fyl2x(void) 398786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 398886797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp; 398986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 399086797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 399186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (fptemp>0.0){ 399286797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = log(fptemp)/log(2.0); /* log2(ST) */ 399386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST1 *= fptemp; 399486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpop(); 399586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 399686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); 399786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 399886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 399986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 400086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 400186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fptan(void) 400286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 400386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp; 400486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 400586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 400686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { 400786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 400886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 400986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = tan(fptemp); 401086797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpush(); 401186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = 1.0; 401286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x400); /* C2 <-- 0 */ 401386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* the above code is for |arg| < 2**52 only */ 401486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 401586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 401686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 401786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fpatan(void) 401886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 401986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp, fpsrcop; 402086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 402186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop = ST1; 402286797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 402386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST1 = atan2(fpsrcop,fptemp); 402486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpop(); 402586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 402686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 402786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fxtract(void) 402886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 402986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU temp; 403086797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int expdif; 403186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 403286797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.d = ST0; 403386797937017f52bff088d02edf64fb931177a7eaJun Nakajima expdif = EXPD(temp) - EXPBIAS; 403486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /*DP exponent bias*/ 403586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = expdif; 403686797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpush(); 403786797937017f52bff088d02edf64fb931177a7eaJun Nakajima BIASEXPONENT(temp); 403886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = temp.d; 403986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 404086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 404186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fprem1(void) 404286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 404386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble dblq, fpsrcop, fptemp; 404486797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU fpsrcop1, fptemp1; 404586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int expdif; 404686797937017f52bff088d02edf64fb931177a7eaJun Nakajima signed long long int q; 404786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 404886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { 404986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = 0.0 / 0.0; /* NaN */ 405086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 405186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 405286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 405386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 405486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop = ST0; 405586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST1; 405686797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop1.d = fpsrcop; 405786797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp1.d = fptemp; 405886797937017f52bff088d02edf64fb931177a7eaJun Nakajima expdif = EXPD(fpsrcop1) - EXPD(fptemp1); 405986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 406086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (expdif < 0) { 406186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* optimisation? taken from the AMD docs */ 406286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 406386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* ST0 is unchanged */ 406486797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 406586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 406686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 406786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (expdif < 53) { 406886797937017f52bff088d02edf64fb931177a7eaJun Nakajima dblq = fpsrcop / fptemp; 406986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* round dblq towards nearest integer */ 407086797937017f52bff088d02edf64fb931177a7eaJun Nakajima dblq = rint(dblq); 407186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = fpsrcop - fptemp * dblq; 407286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 407386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* convert dblq to q by truncating towards zero */ 407486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dblq < 0.0) 407586797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (signed long long int)(-dblq); 407686797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 407786797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (signed long long int)dblq; 407886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 407986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 408086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* (C0,C3,C1) <-- (q2,q1,q0) */ 408186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ 408286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ 408386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ 408486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 408586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; /* C2 <-- 1 */ 408686797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = pow(2.0, expdif - 50); 408786797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop = (ST0 / ST1) / fptemp; 408886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* fpsrcop = integer obtained by chopping */ 408986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop = (fpsrcop < 0.0) ? 409086797937017f52bff088d02edf64fb931177a7eaJun Nakajima -(floor(fabs(fpsrcop))) : floor(fpsrcop); 409186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 -= (ST1 * fpsrcop * fptemp); 409286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 409386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 409486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 409586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fprem(void) 409686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 409786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble dblq, fpsrcop, fptemp; 409886797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU fpsrcop1, fptemp1; 409986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int expdif; 410086797937017f52bff088d02edf64fb931177a7eaJun Nakajima signed long long int q; 410186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 410286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { 410386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = 0.0 / 0.0; /* NaN */ 410486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 410586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 410686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 410786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 410886797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop = (CPU86_LDouble)ST0; 410986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = (CPU86_LDouble)ST1; 411086797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop1.d = fpsrcop; 411186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp1.d = fptemp; 411286797937017f52bff088d02edf64fb931177a7eaJun Nakajima expdif = EXPD(fpsrcop1) - EXPD(fptemp1); 411386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 411486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (expdif < 0) { 411586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* optimisation? taken from the AMD docs */ 411686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 411786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* ST0 is unchanged */ 411886797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 411986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 412086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 412186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ( expdif < 53 ) { 412286797937017f52bff088d02edf64fb931177a7eaJun Nakajima dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/; 412386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* round dblq towards zero */ 412486797937017f52bff088d02edf64fb931177a7eaJun Nakajima dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); 412586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = fpsrcop/*ST0*/ - fptemp * dblq; 412686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 412786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* convert dblq to q by truncating towards zero */ 412886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (dblq < 0.0) 412986797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (signed long long int)(-dblq); 413086797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 413186797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = (signed long long int)dblq; 413286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 413386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 413486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* (C0,C3,C1) <-- (q2,q1,q0) */ 413586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ 413686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ 413786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ 413886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 413986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int N = 32 + (expdif % 32); /* as per AMD docs */ 414086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; /* C2 <-- 1 */ 414186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = pow(2.0, (double)(expdif - N)); 414286797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop = (ST0 / ST1) / fptemp; 414386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* fpsrcop = integer obtained by chopping */ 414486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpsrcop = (fpsrcop < 0.0) ? 414586797937017f52bff088d02edf64fb931177a7eaJun Nakajima -(floor(fabs(fpsrcop))) : floor(fpsrcop); 414686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 -= (ST1 * fpsrcop * fptemp); 414786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 414886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 414986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 415086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fyl2xp1(void) 415186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 415286797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp; 415386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 415486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 415586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((fptemp+1.0)>0.0) { 415686797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ 415786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST1 *= fptemp; 415886797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpop(); 415986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 416086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); 416186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 416286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 416386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 416486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 416586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsqrt(void) 416686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 416786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp; 416886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 416986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 417086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (fptemp<0.0) { 417186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 417286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 417386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 417486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = sqrt(fptemp); 417586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 417686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 417786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsincos(void) 417886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 417986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp; 418086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 418186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 418286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { 418386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 418486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 418586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = sin(fptemp); 418686797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpush(); 418786797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = cos(fptemp); 418886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x400); /* C2 <-- 0 */ 418986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* the above code is for |arg| < 2**63 only */ 419086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 419186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 419286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 419386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_frndint(void) 419486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 419586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = floatx_round_to_int(ST0, &env->fp_status); 419686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 419786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 419886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fscale(void) 419986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 420086797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = ldexp (ST0, (int)(ST1)); 420186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 420286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 420386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsin(void) 420486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 420586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp; 420686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 420786797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 420886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { 420986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 421086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 421186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = sin(fptemp); 421286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x400); /* C2 <-- 0 */ 421386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* the above code is for |arg| < 2**53 only */ 421486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 421586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 421686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 421786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fcos(void) 421886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 421986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble fptemp; 422086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 422186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptemp = ST0; 422286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { 422386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 422486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 422586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST0 = cos(fptemp); 422686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x400); /* C2 <-- 0 */ 422786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* the above code is for |arg5 < 2**63 only */ 422886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 422986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 423086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 423186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fxam_ST0(void) 423286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 423386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU temp; 423486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int expdif; 423586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 423686797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.d = ST0; 423786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 423886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ 423986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (SIGND(temp)) 424086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x200; /* C1 <-- 1 */ 424186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 424286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: test fptags too */ 424386797937017f52bff088d02edf64fb931177a7eaJun Nakajima expdif = EXPD(temp); 424486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (expdif == MAXEXPD) { 424586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef USE_X86LDOUBLE 424686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (MANTD(temp) == 0x8000000000000000ULL) 424786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 424886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (MANTD(temp) == 0) 424986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 425086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x500 /*Infinity*/; 425186797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 425286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x100 /*NaN*/; 425386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else if (expdif == 0) { 425486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (MANTD(temp) == 0) 425586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x4000 /*Zero*/; 425686797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 425786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x4400 /*Denormal*/; 425886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 425986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus |= 0x400; 426086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 426186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 426286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 426386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fstenv(target_ulong ptr, int data32) 426486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 426586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int fpus, fptag, exp, i; 426686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t mant; 426786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU tmp; 426886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 426986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; 427086797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag = 0; 427186797937017f52bff088d02edf64fb931177a7eaJun Nakajima for (i=7; i>=0; i--) { 427286797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag <<= 2; 427386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->fptags[i]) { 427486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag |= 3; 427586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 427686797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp.d = env->fpregs[i].d; 427786797937017f52bff088d02edf64fb931177a7eaJun Nakajima exp = EXPD(tmp); 427886797937017f52bff088d02edf64fb931177a7eaJun Nakajima mant = MANTD(tmp); 427986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (exp == 0 && mant == 0) { 428086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* zero */ 428186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag |= 1; 428286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else if (exp == 0 || exp == MAXEXPD 428386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef USE_X86LDOUBLE 428486797937017f52bff088d02edf64fb931177a7eaJun Nakajima || (mant & (1LL << 63)) == 0 428586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 428686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ) { 428786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* NaNs, infinity, denormal */ 428886797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag |= 2; 428986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 429086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 429186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 429286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (data32) { 429386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 32 bit */ 429486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr, env->fpuc); 429586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 4, fpus); 429686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 8, fptag); 429786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 12, 0); /* fpip */ 429886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 16, 0); /* fpcs */ 429986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 20, 0); /* fpoo */ 430086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 24, 0); /* fpos */ 430186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 430286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* 16 bit */ 430386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr, env->fpuc); 430486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 2, fpus); 430586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 4, fptag); 430686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 6, 0); 430786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 8, 0); 430886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 10, 0); 430986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 12, 0); 431086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 431186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 431286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 431386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fldenv(target_ulong ptr, int data32) 431486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 431586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i, fpus, fptag; 431686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 431786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (data32) { 431886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpuc = lduw(ptr); 431986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpus = lduw(ptr + 4); 432086797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag = lduw(ptr + 8); 432186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 432286797937017f52bff088d02edf64fb931177a7eaJun Nakajima else { 432386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpuc = lduw(ptr); 432486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpus = lduw(ptr + 2); 432586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag = lduw(ptr + 4); 432686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 432786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = (fpus >> 11) & 7; 432886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus = fpus & ~0x3800; 432986797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0;i < 8; i++) { 433086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[i] = ((fptag & 3) == 3); 433186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag >>= 2; 433286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 433386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 433486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 433586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fsave(target_ulong ptr, int data32) 433686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 433786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble tmp; 433886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i; 433986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 434086797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_fstenv(ptr, data32); 434186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 434286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr += (14 << data32); 434386797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0;i < 8; i++) { 434486797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp = ST(i); 434586797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_fstt(tmp, ptr); 434686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr += 10; 434786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 434886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 434986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* fninit */ 435086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus = 0; 435186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = 0; 435286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpuc = 0x37f; 435386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[0] = 1; 435486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[1] = 1; 435586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[2] = 1; 435686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[3] = 1; 435786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[4] = 1; 435886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[5] = 1; 435986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[6] = 1; 436086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[7] = 1; 436186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 436286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 436386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_frstor(target_ulong ptr, int data32) 436486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 436586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble tmp; 436686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i; 436786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 436886797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_fldenv(ptr, data32); 436986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr += (14 << data32); 437086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 437186797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0;i < 8; i++) { 437286797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp = helper_fldt(ptr); 437386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST(i) = tmp; 437486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ptr += 10; 437586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 437686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 437786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 437886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fxsave(target_ulong ptr, int data64) 437986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 438086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int fpus, fptag, i, nb_xmm_regs; 438186797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble tmp; 438286797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong addr; 438386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 438486797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; 438586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag = 0; 438686797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 8; i++) { 438786797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag |= (env->fptags[i] << i); 438886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 438986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr, env->fpuc); 439086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 2, fpus); 439186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stw(ptr + 4, fptag ^ 0xff); 439286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 439386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (data64) { 439486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(ptr + 0x08, 0); /* rip */ 439586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(ptr + 0x10, 0); /* rdp */ 4396f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner } else 439786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 439886797937017f52bff088d02edf64fb931177a7eaJun Nakajima { 439986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 0x08, 0); /* eip */ 440086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 0x0c, 0); /* sel */ 440186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 0x10, 0); /* dp */ 440286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 0x14, 0); /* sel */ 440386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 440486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 440586797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = ptr + 0x20; 440686797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0;i < 8; i++) { 440786797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp = ST(i); 440886797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_fstt(tmp, addr); 440986797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr += 16; 441086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 441186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 441286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cr[4] & CR4_OSFXSR_MASK) { 441386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: finish it */ 441486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 0x18, env->mxcsr); /* mxcsr */ 441586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */ 441686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_CS64_MASK) 441786797937017f52bff088d02edf64fb931177a7eaJun Nakajima nb_xmm_regs = 16; 441886797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 441986797937017f52bff088d02edf64fb931177a7eaJun Nakajima nb_xmm_regs = 8; 442086797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = ptr + 0xa0; 442186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Fast FXSAVE leaves out the XMM registers */ 442286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->efer & MSR_EFER_FFXSR) 442386797937017f52bff088d02edf64fb931177a7eaJun Nakajima || (env->hflags & HF_CPL_MASK) 442486797937017f52bff088d02edf64fb931177a7eaJun Nakajima || !(env->hflags & HF_LMA_MASK)) { 442586797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < nb_xmm_regs; i++) { 442686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(addr, env->xmm_regs[i].XMM_Q(0)); 442786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq(addr + 8, env->xmm_regs[i].XMM_Q(1)); 442886797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr += 16; 442986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 443086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 443186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 443286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 443386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 443486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_fxrstor(target_ulong ptr, int data64) 443586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 443686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i, fpus, fptag, nb_xmm_regs; 443786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDouble tmp; 443886797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong addr; 443986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 444086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpuc = lduw(ptr); 444186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fpus = lduw(ptr + 2); 444286797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag = lduw(ptr + 4); 444386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = (fpus >> 11) & 7; 444486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpus = fpus & ~0x3800; 444586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fptag ^= 0xff; 444686797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0;i < 8; i++) { 444786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fptags[i] = ((fptag >> i) & 1); 444886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 444986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 445086797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = ptr + 0x20; 445186797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0;i < 8; i++) { 445286797937017f52bff088d02edf64fb931177a7eaJun Nakajima tmp = helper_fldt(addr); 445386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ST(i) = tmp; 445486797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr += 16; 445586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 445686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 445786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cr[4] & CR4_OSFXSR_MASK) { 445886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: finish it */ 445986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->mxcsr = ldl(ptr + 0x18); 446086797937017f52bff088d02edf64fb931177a7eaJun Nakajima //ldl(ptr + 0x1c); 446186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->hflags & HF_CS64_MASK) 446286797937017f52bff088d02edf64fb931177a7eaJun Nakajima nb_xmm_regs = 16; 446386797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 446486797937017f52bff088d02edf64fb931177a7eaJun Nakajima nb_xmm_regs = 8; 446586797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = ptr + 0xa0; 446686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Fast FXRESTORE leaves out the XMM registers */ 446786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!(env->efer & MSR_EFER_FFXSR) 446886797937017f52bff088d02edf64fb931177a7eaJun Nakajima || (env->hflags & HF_CPL_MASK) 446986797937017f52bff088d02edf64fb931177a7eaJun Nakajima || !(env->hflags & HF_LMA_MASK)) { 447086797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < nb_xmm_regs; i++) { 447186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->xmm_regs[i].XMM_Q(0) = ldq(addr); 447286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); 447386797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr += 16; 447486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 447586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 447686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 447786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 447886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 447986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifndef USE_X86LDOUBLE 448086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 448186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) 448286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 448386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU temp; 448486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int e; 448586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 448686797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.d = f; 448786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* mantissa */ 448886797937017f52bff088d02edf64fb931177a7eaJun Nakajima *pmant = (MANTD(temp) << 11) | (1LL << 63); 448986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* exponent + sign */ 449086797937017f52bff088d02edf64fb931177a7eaJun Nakajima e = EXPD(temp) - EXPBIAS + 16383; 449186797937017f52bff088d02edf64fb931177a7eaJun Nakajima e |= SIGND(temp) >> 16; 449286797937017f52bff088d02edf64fb931177a7eaJun Nakajima *pexp = e; 449386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 449486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 449586797937017f52bff088d02edf64fb931177a7eaJun NakajimaCPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) 449686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 449786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU temp; 449886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int e; 449986797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t ll; 450086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 450186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: handle overflow ? */ 450286797937017f52bff088d02edf64fb931177a7eaJun Nakajima e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ 450386797937017f52bff088d02edf64fb931177a7eaJun Nakajima e |= (upper >> 4) & 0x800; /* sign */ 450486797937017f52bff088d02edf64fb931177a7eaJun Nakajima ll = (mant >> 11) & ((1LL << 52) - 1); 450586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef __arm__ 450686797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.l.upper = (e << 20) | (ll >> 32); 450786797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.l.lower = ll; 450886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 450986797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.ll = ll | ((uint64_t)e << 52); 451086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 451186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return temp.d; 451286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 451386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 451486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 451586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 451686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) 451786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 451886797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU temp; 451986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 452086797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.d = f; 452186797937017f52bff088d02edf64fb931177a7eaJun Nakajima *pmant = temp.l.lower; 452286797937017f52bff088d02edf64fb931177a7eaJun Nakajima *pexp = temp.l.upper; 452386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 452486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 452586797937017f52bff088d02edf64fb931177a7eaJun NakajimaCPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) 452686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 452786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPU86_LDoubleU temp; 452886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 452986797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.l.upper = upper; 453086797937017f52bff088d02edf64fb931177a7eaJun Nakajima temp.l.lower = mant; 453186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return temp.d; 453286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 453386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 453486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 453586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 453686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 453786797937017f52bff088d02edf64fb931177a7eaJun Nakajima//#define DEBUG_MULDIV 453886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 453986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) 454086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 454186797937017f52bff088d02edf64fb931177a7eaJun Nakajima *plow += a; 454286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* carry test */ 454386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (*plow < a) 454486797937017f52bff088d02edf64fb931177a7eaJun Nakajima (*phigh)++; 454586797937017f52bff088d02edf64fb931177a7eaJun Nakajima *phigh += b; 454686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 454786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 454886797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void neg128(uint64_t *plow, uint64_t *phigh) 454986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 455086797937017f52bff088d02edf64fb931177a7eaJun Nakajima *plow = ~ *plow; 455186797937017f52bff088d02edf64fb931177a7eaJun Nakajima *phigh = ~ *phigh; 455286797937017f52bff088d02edf64fb931177a7eaJun Nakajima add128(plow, phigh, 1, 0); 455386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 455486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 455586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* return TRUE if overflow */ 455686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) 455786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 455886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t q, r, a1, a0; 455986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i, qb, ab; 456086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 456186797937017f52bff088d02edf64fb931177a7eaJun Nakajima a0 = *plow; 456286797937017f52bff088d02edf64fb931177a7eaJun Nakajima a1 = *phigh; 456386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (a1 == 0) { 456486797937017f52bff088d02edf64fb931177a7eaJun Nakajima q = a0 / b; 456586797937017f52bff088d02edf64fb931177a7eaJun Nakajima r = a0 % b; 456686797937017f52bff088d02edf64fb931177a7eaJun Nakajima *plow = q; 456786797937017f52bff088d02edf64fb931177a7eaJun Nakajima *phigh = r; 456886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 456986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (a1 >= b) 457086797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 1; 457186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: use a better algorithm */ 457286797937017f52bff088d02edf64fb931177a7eaJun Nakajima for(i = 0; i < 64; i++) { 457386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ab = a1 >> 63; 457486797937017f52bff088d02edf64fb931177a7eaJun Nakajima a1 = (a1 << 1) | (a0 >> 63); 457586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ab || a1 >= b) { 457686797937017f52bff088d02edf64fb931177a7eaJun Nakajima a1 -= b; 457786797937017f52bff088d02edf64fb931177a7eaJun Nakajima qb = 1; 457886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 457986797937017f52bff088d02edf64fb931177a7eaJun Nakajima qb = 0; 458086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 458186797937017f52bff088d02edf64fb931177a7eaJun Nakajima a0 = (a0 << 1) | qb; 458286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 458386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(DEBUG_MULDIV) 458486797937017f52bff088d02edf64fb931177a7eaJun Nakajima printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", 458586797937017f52bff088d02edf64fb931177a7eaJun Nakajima *phigh, *plow, b, a0, a1); 458686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 458786797937017f52bff088d02edf64fb931177a7eaJun Nakajima *plow = a0; 458886797937017f52bff088d02edf64fb931177a7eaJun Nakajima *phigh = a1; 458986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 459086797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 459186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 459286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 459386797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* return TRUE if overflow */ 459486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) 459586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 459686797937017f52bff088d02edf64fb931177a7eaJun Nakajima int sa, sb; 459786797937017f52bff088d02edf64fb931177a7eaJun Nakajima sa = ((int64_t)*phigh < 0); 459886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (sa) 459986797937017f52bff088d02edf64fb931177a7eaJun Nakajima neg128(plow, phigh); 460086797937017f52bff088d02edf64fb931177a7eaJun Nakajima sb = (b < 0); 460186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (sb) 460286797937017f52bff088d02edf64fb931177a7eaJun Nakajima b = -b; 460386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (div64(plow, phigh, b) != 0) 460486797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 1; 460586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (sa ^ sb) { 460686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (*plow > (1ULL << 63)) 460786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 1; 460886797937017f52bff088d02edf64fb931177a7eaJun Nakajima *plow = - *plow; 460986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 461086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (*plow >= (1ULL << 63)) 461186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 1; 461286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 461386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (sa) 461486797937017f52bff088d02edf64fb931177a7eaJun Nakajima *phigh = - *phigh; 461586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 461686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 461786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 461886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_mulq_EAX_T0(target_ulong t0) 461986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 462086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t r0, r1; 462186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 462286797937017f52bff088d02edf64fb931177a7eaJun Nakajima mulu64(&r0, &r1, EAX, t0); 462386797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = r0; 462486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = r1; 462586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_DST = r0; 462686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = r1; 462786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 462886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 462986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_imulq_EAX_T0(target_ulong t0) 463086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 463186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t r0, r1; 463286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 463386797937017f52bff088d02edf64fb931177a7eaJun Nakajima muls64(&r0, &r1, EAX, t0); 463486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = r0; 463586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = r1; 463686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_DST = r0; 463786797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); 463886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 463986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 464086797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1) 464186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 464286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t r0, r1; 464386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 464486797937017f52bff088d02edf64fb931177a7eaJun Nakajima muls64(&r0, &r1, t0, t1); 464586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_DST = r0; 464686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); 464786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return r0; 464886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 464986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 465086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_divq_EAX(target_ulong t0) 465186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 465286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t r0, r1; 465386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (t0 == 0) { 465486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 465586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 465686797937017f52bff088d02edf64fb931177a7eaJun Nakajima r0 = EAX; 465786797937017f52bff088d02edf64fb931177a7eaJun Nakajima r1 = EDX; 465886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (div64(&r0, &r1, t0)) 465986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 466086797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = r0; 466186797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = r1; 466286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 466386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 466486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_idivq_EAX(target_ulong t0) 466586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 466686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t r0, r1; 466786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (t0 == 0) { 466886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 466986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 467086797937017f52bff088d02edf64fb931177a7eaJun Nakajima r0 = EAX; 467186797937017f52bff088d02edf64fb931177a7eaJun Nakajima r1 = EDX; 467286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (idiv64(&r0, &r1, t0)) 467386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP00_DIVZ); 467486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = r0; 467586797937017f52bff088d02edf64fb931177a7eaJun Nakajima EDX = r1; 467686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 467786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 467886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 467986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void do_hlt(void) 468086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 468186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ 468286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->halted = 1; 468386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = EXCP_HLT; 468486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 468586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 468686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 468786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_hlt(int next_eip_addend) 468886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 468986797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_HLT, 0); 469086797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP += next_eip_addend; 4691f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner 469286797937017f52bff088d02edf64fb931177a7eaJun Nakajima do_hlt(); 469386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 469486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 469586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_monitor(target_ulong ptr) 469686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 469786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((uint32_t)ECX != 0) 469886797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP0D_GPF); 469986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: store address ? */ 470086797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0); 470186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 470286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 470386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_mwait(int next_eip_addend) 470486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 470586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if ((uint32_t)ECX != 0) 470686797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP0D_GPF); 470786797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0); 470886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP += next_eip_addend; 470986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 471086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: not complete but not completely erroneous */ 471186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->cpu_index != 0 || env->next_cpu != NULL) { 471286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* more than one CPU: do not sleep because another CPU may 471386797937017f52bff088d02edf64fb931177a7eaJun Nakajima wake this one */ 471486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 471586797937017f52bff088d02edf64fb931177a7eaJun Nakajima do_hlt(); 471686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 471786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 471886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 471986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_debug(void) 472086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 472186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = EXCP_DEBUG; 472286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 472386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 472486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 472586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_reset_rf(void) 472686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 472786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~RF_MASK; 472886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 472986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 473086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_raise_interrupt(int intno, int next_eip_addend) 473186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 473286797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_interrupt(intno, 1, 0, next_eip_addend); 473386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 473486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 473586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_raise_exception(int exception_index) 473686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 473786797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(exception_index); 473886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 473986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 474086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_cli(void) 474186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 474286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~IF_MASK; 474386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 474486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 474586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_sti(void) 474686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 474786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags |= IF_MASK; 474886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 474986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 475086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if 0 475186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* vm86plus instructions */ 475286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_cli_vm(void) 475386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 475486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~VIF_MASK; 475586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 475686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 475786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_sti_vm(void) 475886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 475986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags |= VIF_MASK; 476086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & VIP_MASK) { 476186797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP0D_GPF); 476286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 476386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 476486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 476586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 476686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_set_inhibit_irq(void) 476786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 476886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags |= HF_INHIBIT_IRQ_MASK; 476986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 477086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 477186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_reset_inhibit_irq(void) 477286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 477386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags &= ~HF_INHIBIT_IRQ_MASK; 477486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 477586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 477686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_boundw(target_ulong a0, int v) 477786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 477886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int low, high; 477986797937017f52bff088d02edf64fb931177a7eaJun Nakajima low = ldsw(a0); 478086797937017f52bff088d02edf64fb931177a7eaJun Nakajima high = ldsw(a0 + 2); 478186797937017f52bff088d02edf64fb931177a7eaJun Nakajima v = (int16_t)v; 478286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (v < low || v > high) { 478386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP05_BOUND); 478486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 478586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 478686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 478786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_boundl(target_ulong a0, int v) 478886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 478986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int low, high; 479086797937017f52bff088d02edf64fb931177a7eaJun Nakajima low = ldl(a0); 479186797937017f52bff088d02edf64fb931177a7eaJun Nakajima high = ldl(a0 + 4); 479286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (v < low || v > high) { 479386797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP05_BOUND); 479486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 479586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 479686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 479786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic float approx_rsqrt(float a) 479886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 479986797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 1.0 / sqrt(a); 480086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 480186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 480286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic float approx_rcp(float a) 480386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 480486797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 1.0 / a; 480586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 480686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 480786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 480886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 480986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define MMUSUFFIX _mmu 481086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 481186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 0 481286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "softmmu_template.h" 481386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 481486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 1 481586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "softmmu_template.h" 481686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 481786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 2 481886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "softmmu_template.h" 481986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 482086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 3 482186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "softmmu_template.h" 482286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 482386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 482486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 482586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if !defined(CONFIG_USER_ONLY) 482686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* try to fill the TLB and return an exception if error. If retaddr is 482786797937017f52bff088d02edf64fb931177a7eaJun Nakajima NULL, it means that the function was called in C code (i.e. not 482886797937017f52bff088d02edf64fb931177a7eaJun Nakajima from generated code or from helper.c) */ 482986797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: fix it to restore all registers */ 483086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) 483186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 483286797937017f52bff088d02edf64fb931177a7eaJun Nakajima TranslationBlock *tb; 483386797937017f52bff088d02edf64fb931177a7eaJun Nakajima int ret; 483486797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned long pc; 483586797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPUX86State *saved_env; 483686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 483786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: hack to restore env in all cases, even if not called from 483886797937017f52bff088d02edf64fb931177a7eaJun Nakajima generated code */ 483986797937017f52bff088d02edf64fb931177a7eaJun Nakajima saved_env = env; 484086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env = cpu_single_env; 484186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 484286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); 484386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ret) { 484486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (retaddr) { 484586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* now we have a real cpu fault */ 484686797937017f52bff088d02edf64fb931177a7eaJun Nakajima pc = (unsigned long)retaddr; 484786797937017f52bff088d02edf64fb931177a7eaJun Nakajima tb = tb_find_pc(pc); 484886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (tb) { 484986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* the PC is inside the translated code. It means that we have 485086797937017f52bff088d02edf64fb931177a7eaJun Nakajima a virtual CPU fault */ 4851f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner cpu_restore_state(tb, env, pc); 485286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 485386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 485486797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception_err(env->exception_index, env->error_code); 485586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 485686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env = saved_env; 485786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 485886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 485986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 486086797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* Secure Virtual Machine helpers */ 486186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 486286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(CONFIG_USER_ONLY) 486386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 486486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmrun(int aflag, int next_eip_addend) 4865f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner{ 486686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 4867f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turnervoid helper_vmmcall(void) 4868f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner{ 486986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 487086797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmload(int aflag) 4871f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner{ 487286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 487386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmsave(int aflag) 4874f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner{ 487586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 487686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_stgi(void) 487786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 487886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 487986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_clgi(void) 488086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 488186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 4882f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turnervoid helper_skinit(void) 4883f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner{ 488486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 488586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_invlpga(int aflag) 4886f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner{ 488786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 4888f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turnervoid helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) 4889f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner{ 489086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 489186797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_svm_check_intercept_param(uint32_t type, uint64_t param) 489286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 489386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 489486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 4895f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turnervoid helper_svm_check_io(uint32_t port, uint32_t param, 489686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t next_eip_addend) 489786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 489886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 489986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else 490086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 490186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void svm_save_seg(target_phys_addr_t addr, 490286797937017f52bff088d02edf64fb931177a7eaJun Nakajima const SegmentCache *sc) 490386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 4904f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stw_phys(addr + offsetof(struct vmcb_seg, selector), 490586797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->selector); 4906f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stq_phys(addr + offsetof(struct vmcb_seg, base), 490786797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->base); 4908f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stl_phys(addr + offsetof(struct vmcb_seg, limit), 490986797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->limit); 4910f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stw_phys(addr + offsetof(struct vmcb_seg, attrib), 491186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); 491286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 4913f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner 491486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc) 491586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 491686797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned int flags; 491786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 491886797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector)); 491986797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base)); 492086797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit)); 492186797937017f52bff088d02edf64fb931177a7eaJun Nakajima flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib)); 492286797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); 492386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 492486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 4925f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turnerstatic inline void svm_load_seg_cache(target_phys_addr_t addr, 492686797937017f52bff088d02edf64fb931177a7eaJun Nakajima CPUState *env, int seg_reg) 492786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 492886797937017f52bff088d02edf64fb931177a7eaJun Nakajima SegmentCache sc1, *sc = &sc1; 492986797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg(addr, sc); 493086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_load_seg_cache(env, seg_reg, sc->selector, 493186797937017f52bff088d02edf64fb931177a7eaJun Nakajima sc->base, sc->limit, sc->flags); 493286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 493386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 493486797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmrun(int aflag, int next_eip_addend) 493586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 493686797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong addr; 493786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t event_inj; 493886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t int_ctl; 493986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 494086797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0); 494186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 494286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (aflag == 2) 494386797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = EAX; 494486797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 494586797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = (uint32_t)EAX; 494686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 494786797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr); 494886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 494986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->vm_vmcb = addr; 495086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 495186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* save the current CPU state in the hsave page */ 495286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); 495386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); 495486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 495586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base); 495686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); 495786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 495886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]); 495986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]); 496086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]); 496186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]); 496286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]); 496386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]); 496486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 496586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); 496686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags()); 496786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 4968f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es), 496986797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_ES]); 4970f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs), 497186797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_CS]); 4972f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss), 497386797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_SS]); 4974f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds), 497586797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_DS]); 497686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 497786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), 497886797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP + next_eip_addend); 497986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP); 498086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX); 498186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 498286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* load the interception bitmaps so we do not need to access the 498386797937017f52bff088d02edf64fb931177a7eaJun Nakajima vmcb in svm mode */ 498486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)); 498586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read)); 498686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write)); 498786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read)); 498886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write)); 498986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions)); 499086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 499186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* enable intercepts */ 499286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags |= HF_SVMI_MASK; 499386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 499486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset)); 499586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 499686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base)); 499786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit)); 499886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 499986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base)); 500086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit)); 500186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 500286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* clear exit_info_2 so we behave like the real hardware */ 500386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); 500486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 500586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0))); 500686797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4))); 500786797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3))); 500886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2)); 500986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); 501086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); 501186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (int_ctl & V_INTR_MASKING_MASK) { 501286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->v_tpr = int_ctl & V_TPR_MASK; 501386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 |= HF2_VINTR_MASK; 501486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->eflags & IF_MASK) 501586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 |= HF2_HIF_MASK; 501686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 501786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 5018f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner cpu_load_efer(env, 501986797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer))); 502086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags = 0; 502186797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)), 502286797937017f52bff088d02edf64fb931177a7eaJun Nakajima ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); 502386797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 502486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 502586797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es), 502686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_ES); 502786797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs), 502886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_CS); 502986797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss), 503086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_SS); 503186797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds), 503286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_DS); 503386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 503486797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip)); 503586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip = EIP; 503686797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp)); 503786797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax)); 503886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7)); 503986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6)); 504086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl))); 504186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 504286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* FIXME: guest state consistency checks */ 504386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 504486797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { 504586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case TLB_CONTROL_DO_NOTHING: 504686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 504786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case TLB_CONTROL_FLUSH_ALL_ASID: 504886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* FIXME: this is not 100% correct but should work for now */ 504986797937017f52bff088d02edf64fb931177a7eaJun Nakajima tlb_flush(env, 1); 505086797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 505186797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 505286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 505386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 |= HF2_GIF_MASK; 505486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 505586797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (int_ctl & V_IRQ_MASK) { 505686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->interrupt_request |= CPU_INTERRUPT_VIRQ; 505786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 505886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 505986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* maybe we need to inject an event */ 506086797937017f52bff088d02edf64fb931177a7eaJun Nakajima event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); 506186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (event_inj & SVM_EVTINJ_VALID) { 506286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK; 506386797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR; 506486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)); 506586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 506686797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err); 506786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* FIXME: need to implement valid_err */ 506886797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch (event_inj & SVM_EVTINJ_TYPE_MASK) { 506986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EVTINJ_TYPE_INTR: 507086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = vector; 507186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->error_code = event_inj_err; 507286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_is_int = 0; 507386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_next_eip = -1; 507486797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR"); 507586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: is it always correct ? */ 507686797937017f52bff088d02edf64fb931177a7eaJun Nakajima do_interrupt(vector, 0, 0, 0, 1); 507786797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 507886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EVTINJ_TYPE_NMI: 507986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = EXCP02_NMI; 508086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->error_code = event_inj_err; 508186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_is_int = 0; 508286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_next_eip = EIP; 508386797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI"); 508486797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 508586797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 508686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EVTINJ_TYPE_EXEPT: 508786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = vector; 508886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->error_code = event_inj_err; 508986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_is_int = 0; 509086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_next_eip = -1; 509186797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT"); 509286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 509386797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 509486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EVTINJ_TYPE_SOFT: 509586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = vector; 509686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->error_code = event_inj_err; 509786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_is_int = 1; 509886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_next_eip = EIP; 509986797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT"); 510086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 510186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 510286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 510386797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code); 510486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 510586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 510686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 510786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmmcall(void) 510886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 510986797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0); 511086797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP06_ILLOP); 511186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 511286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 511386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmload(int aflag) 511486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 511586797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong addr; 511686797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0); 511786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 511886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (aflag == 2) 511986797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = EAX; 512086797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 512186797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = (uint32_t)EAX; 512286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 512386797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", 512486797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), 512586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_FS].base); 512686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 512786797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs), 512886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_FS); 512986797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs), 513086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_GS); 513186797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg(addr + offsetof(struct vmcb, save.tr), 513286797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->tr); 513386797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg(addr + offsetof(struct vmcb, save.ldtr), 513486797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->ldt); 513586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 513686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 513786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base)); 513886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar)); 513986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar)); 514086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask)); 514186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 514286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->star = ldq_phys(addr + offsetof(struct vmcb, save.star)); 514386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs)); 514486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp)); 514586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip)); 514686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 514786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 514886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmsave(int aflag) 514986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 515086797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong addr; 515186797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0); 515286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 515386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (aflag == 2) 515486797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = EAX; 515586797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 515686797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = (uint32_t)EAX; 515786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 515886797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", 515986797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), 516086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->segs[R_FS].base); 516186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 5162f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(addr + offsetof(struct vmcb, save.fs), 516386797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_FS]); 5164f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(addr + offsetof(struct vmcb, save.gs), 516586797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_GS]); 5166f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(addr + offsetof(struct vmcb, save.tr), 516786797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->tr); 5168f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(addr + offsetof(struct vmcb, save.ldtr), 516986797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->ldt); 517086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 517186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 517286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase); 517386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar); 517486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar); 517586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask); 517686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 517786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.star), env->star); 517886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); 517986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp); 518086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip); 518186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 518286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 518386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_stgi(void) 518486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 518586797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_STGI, 0); 518686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 |= HF2_GIF_MASK; 518786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 518886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 518986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_clgi(void) 519086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 519186797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0); 519286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 &= ~HF2_GIF_MASK; 519386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 519486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 519586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_skinit(void) 519686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 519786797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0); 519886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: not implemented */ 519986797937017f52bff088d02edf64fb931177a7eaJun Nakajima raise_exception(EXCP06_ILLOP); 520086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 520186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 520286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_invlpga(int aflag) 520386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 520486797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong addr; 520586797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0); 5206f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner 520786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (aflag == 2) 520886797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = EAX; 520986797937017f52bff088d02edf64fb931177a7eaJun Nakajima else 521086797937017f52bff088d02edf64fb931177a7eaJun Nakajima addr = (uint32_t)EAX; 521186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 521286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* XXX: could use the ASID to see if it is needed to do the 521386797937017f52bff088d02edf64fb931177a7eaJun Nakajima flush */ 521486797937017f52bff088d02edf64fb931177a7eaJun Nakajima tlb_flush_page(env, addr); 521586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 521686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 521786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_svm_check_intercept_param(uint32_t type, uint64_t param) 521886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 521986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (likely(!(env->hflags & HF_SVMI_MASK))) 522086797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 522186797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch(type) { 522286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: 522386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) { 522486797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 522586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 522686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 522786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: 522886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) { 522986797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 523086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 523186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 523286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7: 523386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) { 523486797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 523586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 523686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 523786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7: 523886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) { 523986797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 524086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 524186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 524286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31: 524386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) { 524486797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 524586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 524686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 524786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case SVM_EXIT_MSR: 524886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) { 524986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* FIXME: this should be read in at vmrun (faster this way?) */ 525086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa)); 525186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t t0, t1; 525286797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch((uint32_t)ECX) { 525386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 0 ... 0x1fff: 525486797937017f52bff088d02edf64fb931177a7eaJun Nakajima t0 = (ECX * 2) % 8; 525586797937017f52bff088d02edf64fb931177a7eaJun Nakajima t1 = ECX / 8; 525686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 525786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 0xc0000000 ... 0xc0001fff: 525886797937017f52bff088d02edf64fb931177a7eaJun Nakajima t0 = (8192 + ECX - 0xc0000000) * 2; 525986797937017f52bff088d02edf64fb931177a7eaJun Nakajima t1 = (t0 / 8); 526086797937017f52bff088d02edf64fb931177a7eaJun Nakajima t0 %= 8; 526186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 526286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 0xc0010000 ... 0xc0011fff: 526386797937017f52bff088d02edf64fb931177a7eaJun Nakajima t0 = (16384 + ECX - 0xc0010000) * 2; 526486797937017f52bff088d02edf64fb931177a7eaJun Nakajima t1 = (t0 / 8); 526586797937017f52bff088d02edf64fb931177a7eaJun Nakajima t0 %= 8; 526686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 526786797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 526886797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 526986797937017f52bff088d02edf64fb931177a7eaJun Nakajima t0 = 0; 527086797937017f52bff088d02edf64fb931177a7eaJun Nakajima t1 = 0; 527186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 527286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 527386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (ldub_phys(addr + t1) & ((1 << param) << t0)) 527486797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 527586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 527686797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 527786797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 527886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) { 527986797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(type, param); 528086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 528186797937017f52bff088d02edf64fb931177a7eaJun Nakajima break; 528286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 528386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 528486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 5285f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turnervoid helper_svm_check_io(uint32_t port, uint32_t param, 528686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t next_eip_addend) 528786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 528886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) { 528986797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* FIXME: this should be read in at vmrun (faster this way?) */ 529086797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); 529186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint16_t mask = (1 << ((param >> 4) & 7)) - 1; 529286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if(lduw_phys(addr + port / 8) & (mask << (port & 7))) { 529386797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* next EIP */ 5294f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 529586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eip + next_eip_addend); 529686797937017f52bff088d02edf64fb931177a7eaJun Nakajima helper_vmexit(SVM_EXIT_IOIO, param | (port << 16)); 529786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 529886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 529986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 530086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 530186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* Note: currently only 32 bits of exit_code are used */ 530286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) 530386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 530486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint32_t int_ctl; 530586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 530686797937017f52bff088d02edf64fb931177a7eaJun Nakajima qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", 530786797937017f52bff088d02edf64fb931177a7eaJun Nakajima exit_code, exit_info_1, 530886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), 530986797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP); 531086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 531186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if(env->hflags & HF_INHIBIT_IRQ_MASK) { 531286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK); 531386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags &= ~HF_INHIBIT_IRQ_MASK; 531486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else { 531586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); 531686797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 531786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 531886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Save the VM state in the vmcb */ 5319f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es), 532086797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_ES]); 5321f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs), 532286797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_CS]); 5323f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss), 532486797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_SS]); 5325f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds), 532686797937017f52bff088d02edf64fb931177a7eaJun Nakajima &env->segs[R_DS]); 532786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 532886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); 532986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); 533086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 533186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base); 533286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); 533386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 533486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer); 533586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]); 533686797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]); 533786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); 533886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); 533986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 534086797937017f52bff088d02edf64fb931177a7eaJun Nakajima int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); 534186797937017f52bff088d02edf64fb931177a7eaJun Nakajima int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK); 534286797937017f52bff088d02edf64fb931177a7eaJun Nakajima int_ctl |= env->v_tpr & V_TPR_MASK; 534386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (env->interrupt_request & CPU_INTERRUPT_VIRQ) 534486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int_ctl |= V_IRQ_MASK; 534586797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); 534686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 534786797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags()); 534886797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip); 534986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP); 535086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX); 535186797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]); 535286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]); 535386797937017f52bff088d02edf64fb931177a7eaJun Nakajima stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK); 535486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 535586797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Reload the host state from vm_hsave */ 535686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); 535786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags &= ~HF_SVMI_MASK; 535886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept = 0; 535986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->intercept_exceptions = 0; 536086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; 536186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->tsc_offset = 0; 536286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 536386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base)); 536486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit)); 536586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 536686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base)); 536786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit)); 536886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 536986797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK); 537086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4))); 537186797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3))); 537286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* we need to set the efer after the crs so the hidden flags get 537386797937017f52bff088d02edf64fb931177a7eaJun Nakajima set properly */ 5374f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner cpu_load_efer(env, 537586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer))); 537686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags = 0; 537786797937017f52bff088d02edf64fb931177a7eaJun Nakajima load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)), 537886797937017f52bff088d02edf64fb931177a7eaJun Nakajima ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); 537986797937017f52bff088d02edf64fb931177a7eaJun Nakajima CC_OP = CC_OP_EFLAGS; 538086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 538186797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es), 538286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_ES); 538386797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs), 538486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_CS); 538586797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss), 538686797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_SS); 538786797937017f52bff088d02edf64fb931177a7eaJun Nakajima svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds), 538886797937017f52bff088d02edf64fb931177a7eaJun Nakajima env, R_DS); 538986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 539086797937017f52bff088d02edf64fb931177a7eaJun Nakajima EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip)); 539186797937017f52bff088d02edf64fb931177a7eaJun Nakajima ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp)); 539286797937017f52bff088d02edf64fb931177a7eaJun Nakajima EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax)); 539386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 539486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6)); 539586797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7)); 539686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 539786797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* other setups */ 539886797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_x86_set_cpl(env, 0); 539986797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); 540086797937017f52bff088d02edf64fb931177a7eaJun Nakajima stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1); 540186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 540286797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info), 540386797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj))); 540486797937017f52bff088d02edf64fb931177a7eaJun Nakajima stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err), 540586797937017f52bff088d02edf64fb931177a7eaJun Nakajima ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err))); 540686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 540786797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->hflags2 &= ~HF2_GIF_MASK; 540886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* FIXME: Resets the current ASID register to zero (host ASID). */ 540986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 541086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ 541186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 541286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Clears the TSC_OFFSET inside the processor. */ 541386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 541486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* If the host is in PAE mode, the processor reloads the host's PDPEs 541586797937017f52bff088d02edf64fb931177a7eaJun Nakajima from the page table indicated the host's CR3. If the PDPEs contain 541686797937017f52bff088d02edf64fb931177a7eaJun Nakajima illegal state, the processor causes a shutdown. */ 541786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 541886797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Forces CR0.PE = 1, RFLAGS.VM = 0. */ 541986797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->cr[0] |= CR0_PE_MASK; 542086797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->eflags &= ~VM_MASK; 542186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 542286797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Disables all breakpoints in the host DR7 register. */ 542386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 542486797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* Checks the reloaded host state for consistency. */ 542586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 542686797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* If the host's rIP reloaded by #VMEXIT is outside the limit of the 542786797937017f52bff088d02edf64fb931177a7eaJun Nakajima host's code segment or non-canonical (in the case of long mode), a 542886797937017f52bff088d02edf64fb931177a7eaJun Nakajima #GP fault is delivered inside the host.) */ 542986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 543086797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* remove any pending exception */ 543186797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->exception_index = -1; 543286797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->error_code = 0; 543386797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->old_exception = -1; 543486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 543586797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_loop_exit(); 543686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 543786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 543886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 543986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 544086797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* MMX/SSE */ 544186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: optimize by storing fptt and fptags in the static cpu state */ 544286797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_enter_mmx(void) 544386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 544486797937017f52bff088d02edf64fb931177a7eaJun Nakajima env->fpstt = 0; 544586797937017f52bff088d02edf64fb931177a7eaJun Nakajima *(uint32_t *)(env->fptags) = 0; 544686797937017f52bff088d02edf64fb931177a7eaJun Nakajima *(uint32_t *)(env->fptags + 4) = 0; 544786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 544886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 544986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_emms(void) 545086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 545186797937017f52bff088d02edf64fb931177a7eaJun Nakajima /* set to empty state */ 545286797937017f52bff088d02edf64fb931177a7eaJun Nakajima *(uint32_t *)(env->fptags) = 0x01010101; 545386797937017f52bff088d02edf64fb931177a7eaJun Nakajima *(uint32_t *)(env->fptags + 4) = 0x01010101; 545486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 545586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 545686797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: suppress */ 545786797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid helper_movq(void *d, void *s) 545886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 545986797937017f52bff088d02edf64fb931177a7eaJun Nakajima *(uint64_t *)d = *(uint64_t *)s; 546086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 546186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 546286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 0 546386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "ops_sse.h" 546486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 546586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 1 546686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "ops_sse.h" 546786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 546886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 0 546986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "helper_template.h" 547086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#undef SHIFT 547186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 547286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 1 547386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "helper_template.h" 547486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#undef SHIFT 547586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 547686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 2 547786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "helper_template.h" 547886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#undef SHIFT 547986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 548086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 548186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 548286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SHIFT 3 548386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "helper_template.h" 548486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#undef SHIFT 548586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 548686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 548786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 548886797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* bit operations */ 548986797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_bsf(target_ulong t0) 549086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 549186797937017f52bff088d02edf64fb931177a7eaJun Nakajima int count; 549286797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong res; 549386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 549486797937017f52bff088d02edf64fb931177a7eaJun Nakajima res = t0; 549586797937017f52bff088d02edf64fb931177a7eaJun Nakajima count = 0; 549686797937017f52bff088d02edf64fb931177a7eaJun Nakajima while ((res & 1) == 0) { 549786797937017f52bff088d02edf64fb931177a7eaJun Nakajima count++; 549886797937017f52bff088d02edf64fb931177a7eaJun Nakajima res >>= 1; 549986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 550086797937017f52bff088d02edf64fb931177a7eaJun Nakajima return count; 550186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 550286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 550386797937017f52bff088d02edf64fb931177a7eaJun Nakajimatarget_ulong helper_bsr(target_ulong t0) 550486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 550586797937017f52bff088d02edf64fb931177a7eaJun Nakajima int count; 550686797937017f52bff088d02edf64fb931177a7eaJun Nakajima target_ulong res, mask; 5507f645f7d6fd841e39524e5df8c1a7fd8347f92ac1David 'Digit' Turner 550886797937017f52bff088d02edf64fb931177a7eaJun Nakajima res = t0; 550986797937017f52bff088d02edf64fb931177a7eaJun Nakajima count = TARGET_LONG_BITS - 1; 551086797937017f52bff088d02edf64fb931177a7eaJun Nakajima mask = (target_ulong)1 << (TARGET_LONG_BITS - 1); 551186797937017f52bff088d02edf64fb931177a7eaJun Nakajima while ((res & mask) == 0) { 551286797937017f52bff088d02edf64fb931177a7eaJun Nakajima count--; 551386797937017f52bff088d02edf64fb931177a7eaJun Nakajima res <<= 1; 551486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 551586797937017f52bff088d02edf64fb931177a7eaJun Nakajima return count; 551686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 551786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 551886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 551986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int compute_all_eflags(void) 552086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 552186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return CC_SRC; 552286797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 552386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 552486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int compute_c_eflags(void) 552586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 552686797937017f52bff088d02edf64fb931177a7eaJun Nakajima return CC_SRC & CC_C; 552786797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 552886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 552986797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint32_t helper_cc_compute_all(int op) 553086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 553186797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch (op) { 553286797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: /* should never happen */ return 0; 553386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 553486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_EFLAGS: return compute_all_eflags(); 553586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 553686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULB: return compute_all_mulb(); 553786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULW: return compute_all_mulw(); 553886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULL: return compute_all_mull(); 553986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 554086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDB: return compute_all_addb(); 554186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDW: return compute_all_addw(); 554286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDL: return compute_all_addl(); 554386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 554486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCB: return compute_all_adcb(); 554586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCW: return compute_all_adcw(); 554686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCL: return compute_all_adcl(); 554786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 554886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBB: return compute_all_subb(); 554986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBW: return compute_all_subw(); 555086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBL: return compute_all_subl(); 555186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 555286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBB: return compute_all_sbbb(); 555386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBW: return compute_all_sbbw(); 555486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBL: return compute_all_sbbl(); 555586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 555686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICB: return compute_all_logicb(); 555786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICW: return compute_all_logicw(); 555886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICL: return compute_all_logicl(); 555986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 556086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCB: return compute_all_incb(); 556186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCW: return compute_all_incw(); 556286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCL: return compute_all_incl(); 556386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 556486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECB: return compute_all_decb(); 556586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECW: return compute_all_decw(); 556686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECL: return compute_all_decl(); 556786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 556886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLB: return compute_all_shlb(); 556986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLW: return compute_all_shlw(); 557086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLL: return compute_all_shll(); 557186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 557286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARB: return compute_all_sarb(); 557386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARW: return compute_all_sarw(); 557486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARL: return compute_all_sarl(); 557586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 557686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 557786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULQ: return compute_all_mulq(); 557886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 557986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDQ: return compute_all_addq(); 558086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 558186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCQ: return compute_all_adcq(); 558286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 558386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBQ: return compute_all_subq(); 558486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 558586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBQ: return compute_all_sbbq(); 558686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 558786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICQ: return compute_all_logicq(); 558886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 558986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCQ: return compute_all_incq(); 559086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 559186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECQ: return compute_all_decq(); 559286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 559386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLQ: return compute_all_shlq(); 559486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 559586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARQ: return compute_all_sarq(); 559686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 559786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 559886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 559986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 560086797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint32_t helper_cc_compute_c(int op) 560186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 560286797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch (op) { 560386797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: /* should never happen */ return 0; 560486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 560586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_EFLAGS: return compute_c_eflags(); 560686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 560786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULB: return compute_c_mull(); 560886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULW: return compute_c_mull(); 560986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULL: return compute_c_mull(); 561086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 561186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDB: return compute_c_addb(); 561286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDW: return compute_c_addw(); 561386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDL: return compute_c_addl(); 561486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 561586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCB: return compute_c_adcb(); 561686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCW: return compute_c_adcw(); 561786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCL: return compute_c_adcl(); 561886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 561986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBB: return compute_c_subb(); 562086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBW: return compute_c_subw(); 562186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBL: return compute_c_subl(); 562286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 562386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBB: return compute_c_sbbb(); 562486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBW: return compute_c_sbbw(); 562586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBL: return compute_c_sbbl(); 562686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 562786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICB: return compute_c_logicb(); 562886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICW: return compute_c_logicw(); 562986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICL: return compute_c_logicl(); 563086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 563186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCB: return compute_c_incl(); 563286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCW: return compute_c_incl(); 563386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCL: return compute_c_incl(); 563486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 563586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECB: return compute_c_incl(); 563686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECW: return compute_c_incl(); 563786797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECL: return compute_c_incl(); 563886797937017f52bff088d02edf64fb931177a7eaJun Nakajima 563986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLB: return compute_c_shlb(); 564086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLW: return compute_c_shlw(); 564186797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLL: return compute_c_shll(); 564286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 564386797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARB: return compute_c_sarl(); 564486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARW: return compute_c_sarl(); 564586797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARL: return compute_c_sarl(); 564686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 564786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_X86_64 564886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_MULQ: return compute_c_mull(); 564986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 565086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADDQ: return compute_c_addq(); 565186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 565286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_ADCQ: return compute_c_adcq(); 565386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 565486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SUBQ: return compute_c_subq(); 565586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 565686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SBBQ: return compute_c_sbbq(); 565786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 565886797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_LOGICQ: return compute_c_logicq(); 565986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 566086797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_INCQ: return compute_c_incl(); 566186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 566286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_DECQ: return compute_c_incl(); 566386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 566486797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SHLQ: return compute_c_shlq(); 566586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 566686797937017f52bff088d02edf64fb931177a7eaJun Nakajima case CC_OP_SARQ: return compute_c_sarl(); 566786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif 566886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 566986797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 5670