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