~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to target/i386/mem_helper.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  x86 memory access helpers
 
3
 *
 
4
 *  Copyright (c) 2003 Fabrice Bellard
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include "qemu/osdep.h"
 
21
#include "cpu.h"
 
22
#include "exec/helper-proto.h"
 
23
#include "exec/exec-all.h"
 
24
#include "exec/cpu_ldst.h"
 
25
#include "qemu/int128.h"
 
26
#include "tcg.h"
 
27
 
 
28
void helper_cmpxchg8b_unlocked(CPUX86State *env, target_ulong a0)
 
29
{
 
30
    uintptr_t ra = GETPC();
 
31
    uint64_t oldv, cmpv, newv;
 
32
    int eflags;
 
33
 
 
34
    eflags = cpu_cc_compute_all(env, CC_OP);
 
35
 
 
36
    cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]);
 
37
    newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]);
 
38
 
 
39
    oldv = cpu_ldq_data_ra(env, a0, ra);
 
40
    newv = (cmpv == oldv ? newv : oldv);
 
41
    /* always do the store */
 
42
    cpu_stq_data_ra(env, a0, newv, ra);
 
43
 
 
44
    if (oldv == cmpv) {
 
45
        eflags |= CC_Z;
 
46
    } else {
 
47
        env->regs[R_EAX] = (uint32_t)oldv;
 
48
        env->regs[R_EDX] = (uint32_t)(oldv >> 32);
 
49
        eflags &= ~CC_Z;
 
50
    }
 
51
    CC_SRC = eflags;
 
52
}
 
53
 
 
54
void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
 
55
{
 
56
#ifdef CONFIG_ATOMIC64
 
57
    uint64_t oldv, cmpv, newv;
 
58
    int eflags;
 
59
 
 
60
    eflags = cpu_cc_compute_all(env, CC_OP);
 
61
 
 
62
    cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]);
 
63
    newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]);
 
64
 
 
65
#ifdef CONFIG_USER_ONLY
 
66
    {
 
67
        uint64_t *haddr = g2h(a0);
 
68
        cmpv = cpu_to_le64(cmpv);
 
69
        newv = cpu_to_le64(newv);
 
70
        oldv = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
 
71
        oldv = le64_to_cpu(oldv);
 
72
    }
 
73
#else
 
74
    {
 
75
        uintptr_t ra = GETPC();
 
76
        int mem_idx = cpu_mmu_index(env, false);
 
77
        TCGMemOpIdx oi = make_memop_idx(MO_TEQ, mem_idx);
 
78
        oldv = helper_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra);
 
79
    }
 
80
#endif
 
81
 
 
82
    if (oldv == cmpv) {
 
83
        eflags |= CC_Z;
 
84
    } else {
 
85
        env->regs[R_EAX] = (uint32_t)oldv;
 
86
        env->regs[R_EDX] = (uint32_t)(oldv >> 32);
 
87
        eflags &= ~CC_Z;
 
88
    }
 
89
    CC_SRC = eflags;
 
90
#else
 
91
    cpu_loop_exit_atomic(ENV_GET_CPU(env), GETPC());
 
92
#endif /* CONFIG_ATOMIC64 */
 
93
}
 
94
 
 
95
#ifdef TARGET_X86_64
 
96
void helper_cmpxchg16b_unlocked(CPUX86State *env, target_ulong a0)
 
97
{
 
98
    uintptr_t ra = GETPC();
 
99
    Int128 oldv, cmpv, newv;
 
100
    uint64_t o0, o1;
 
101
    int eflags;
 
102
    bool success;
 
103
 
 
104
    if ((a0 & 0xf) != 0) {
 
105
        raise_exception_ra(env, EXCP0D_GPF, GETPC());
 
106
    }
 
107
    eflags = cpu_cc_compute_all(env, CC_OP);
 
108
 
 
109
    cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]);
 
110
    newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]);
 
111
 
 
112
    o0 = cpu_ldq_data_ra(env, a0 + 0, ra);
 
113
    o1 = cpu_ldq_data_ra(env, a0 + 8, ra);
 
114
 
 
115
    oldv = int128_make128(o0, o1);
 
116
    success = int128_eq(oldv, cmpv);
 
117
    if (!success) {
 
118
        newv = oldv;
 
119
    }
 
120
 
 
121
    cpu_stq_data_ra(env, a0 + 0, int128_getlo(newv), ra);
 
122
    cpu_stq_data_ra(env, a0 + 8, int128_gethi(newv), ra);
 
123
 
 
124
    if (success) {
 
125
        eflags |= CC_Z;
 
126
    } else {
 
127
        env->regs[R_EAX] = int128_getlo(oldv);
 
128
        env->regs[R_EDX] = int128_gethi(oldv);
 
129
        eflags &= ~CC_Z;
 
130
    }
 
131
    CC_SRC = eflags;
 
132
}
 
133
 
 
134
void helper_cmpxchg16b(CPUX86State *env, target_ulong a0)
 
135
{
 
136
    uintptr_t ra = GETPC();
 
137
 
 
138
    if ((a0 & 0xf) != 0) {
 
139
        raise_exception_ra(env, EXCP0D_GPF, ra);
 
140
    } else {
 
141
#ifndef CONFIG_ATOMIC128
 
142
        cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
 
143
#else
 
144
        int eflags = cpu_cc_compute_all(env, CC_OP);
 
145
 
 
146
        Int128 cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]);
 
147
        Int128 newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]);
 
148
 
 
149
        int mem_idx = cpu_mmu_index(env, false);
 
150
        TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
 
151
        Int128 oldv = helper_atomic_cmpxchgo_le_mmu(env, a0, cmpv,
 
152
                                                    newv, oi, ra);
 
153
 
 
154
        if (int128_eq(oldv, cmpv)) {
 
155
            eflags |= CC_Z;
 
156
        } else {
 
157
            env->regs[R_EAX] = int128_getlo(oldv);
 
158
            env->regs[R_EDX] = int128_gethi(oldv);
 
159
            eflags &= ~CC_Z;
 
160
        }
 
161
        CC_SRC = eflags;
 
162
#endif
 
163
    }
 
164
}
 
165
#endif
 
166
 
 
167
void helper_boundw(CPUX86State *env, target_ulong a0, int v)
 
168
{
 
169
    int low, high;
 
170
 
 
171
    low = cpu_ldsw_data_ra(env, a0, GETPC());
 
172
    high = cpu_ldsw_data_ra(env, a0 + 2, GETPC());
 
173
    v = (int16_t)v;
 
174
    if (v < low || v > high) {
 
175
        if (env->hflags & HF_MPX_EN_MASK) {
 
176
            env->bndcs_regs.sts = 0;
 
177
        }
 
178
        raise_exception_ra(env, EXCP05_BOUND, GETPC());
 
179
    }
 
180
}
 
181
 
 
182
void helper_boundl(CPUX86State *env, target_ulong a0, int v)
 
183
{
 
184
    int low, high;
 
185
 
 
186
    low = cpu_ldl_data_ra(env, a0, GETPC());
 
187
    high = cpu_ldl_data_ra(env, a0 + 4, GETPC());
 
188
    if (v < low || v > high) {
 
189
        if (env->hflags & HF_MPX_EN_MASK) {
 
190
            env->bndcs_regs.sts = 0;
 
191
        }
 
192
        raise_exception_ra(env, EXCP05_BOUND, GETPC());
 
193
    }
 
194
}
 
195
 
 
196
#if !defined(CONFIG_USER_ONLY)
 
197
/* try to fill the TLB and return an exception if error. If retaddr is
 
198
 * NULL, it means that the function was called in C code (i.e. not
 
199
 * from generated code or from helper.c)
 
200
 */
 
201
/* XXX: fix it to restore all registers */
 
202
void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
 
203
              int mmu_idx, uintptr_t retaddr)
 
204
{
 
205
    int ret;
 
206
 
 
207
    ret = x86_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
 
208
    if (ret) {
 
209
        X86CPU *cpu = X86_CPU(cs);
 
210
        CPUX86State *env = &cpu->env;
 
211
 
 
212
        raise_exception_err_ra(env, cs->exception_index, env->error_code, retaddr);
 
213
    }
 
214
}
 
215
#endif