1 | /* |
2 | * x86 MPX helpers |
3 | * |
4 | * Copyright (c) 2015 Red Hat, Inc. |
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/cpu_ldst.h" |
24 | #include "exec/exec-all.h" |
25 | |
26 | |
27 | void helper_bndck(CPUX86State *env, uint32_t fail) |
28 | { |
29 | if (unlikely(fail)) { |
30 | env->bndcs_regs.sts = 1; |
31 | raise_exception_ra(env, EXCP05_BOUND, GETPC()); |
32 | } |
33 | } |
34 | |
35 | static uint64_t lookup_bte64(CPUX86State *env, uint64_t base, uintptr_t ra) |
36 | { |
37 | uint64_t bndcsr, bde, bt; |
38 | |
39 | if ((env->hflags & HF_CPL_MASK) == 3) { |
40 | bndcsr = env->bndcs_regs.cfgu; |
41 | } else { |
42 | bndcsr = env->msr_bndcfgs; |
43 | } |
44 | |
45 | bde = (extract64(base, 20, 28) << 3) + (extract64(bndcsr, 20, 44) << 12); |
46 | bt = cpu_ldq_data_ra(env, bde, ra); |
47 | if ((bt & 1) == 0) { |
48 | env->bndcs_regs.sts = bde | 2; |
49 | raise_exception_ra(env, EXCP05_BOUND, ra); |
50 | } |
51 | |
52 | return (extract64(base, 3, 17) << 5) + (bt & ~7); |
53 | } |
54 | |
55 | static uint32_t lookup_bte32(CPUX86State *env, uint32_t base, uintptr_t ra) |
56 | { |
57 | uint32_t bndcsr, bde, bt; |
58 | |
59 | if ((env->hflags & HF_CPL_MASK) == 3) { |
60 | bndcsr = env->bndcs_regs.cfgu; |
61 | } else { |
62 | bndcsr = env->msr_bndcfgs; |
63 | } |
64 | |
65 | bde = (extract32(base, 12, 20) << 2) + (bndcsr & TARGET_PAGE_MASK); |
66 | bt = cpu_ldl_data_ra(env, bde, ra); |
67 | if ((bt & 1) == 0) { |
68 | env->bndcs_regs.sts = bde | 2; |
69 | raise_exception_ra(env, EXCP05_BOUND, ra); |
70 | } |
71 | |
72 | return (extract32(base, 2, 10) << 4) + (bt & ~3); |
73 | } |
74 | |
75 | uint64_t helper_bndldx64(CPUX86State *env, target_ulong base, target_ulong ptr) |
76 | { |
77 | uintptr_t ra = GETPC(); |
78 | uint64_t bte, lb, ub, pt; |
79 | |
80 | bte = lookup_bte64(env, base, ra); |
81 | lb = cpu_ldq_data_ra(env, bte, ra); |
82 | ub = cpu_ldq_data_ra(env, bte + 8, ra); |
83 | pt = cpu_ldq_data_ra(env, bte + 16, ra); |
84 | |
85 | if (pt != ptr) { |
86 | lb = ub = 0; |
87 | } |
88 | env->mmx_t0.MMX_Q(0) = ub; |
89 | return lb; |
90 | } |
91 | |
92 | uint64_t helper_bndldx32(CPUX86State *env, target_ulong base, target_ulong ptr) |
93 | { |
94 | uintptr_t ra = GETPC(); |
95 | uint32_t bte, lb, ub, pt; |
96 | |
97 | bte = lookup_bte32(env, base, ra); |
98 | lb = cpu_ldl_data_ra(env, bte, ra); |
99 | ub = cpu_ldl_data_ra(env, bte + 4, ra); |
100 | pt = cpu_ldl_data_ra(env, bte + 8, ra); |
101 | |
102 | if (pt != ptr) { |
103 | lb = ub = 0; |
104 | } |
105 | return ((uint64_t)ub << 32) | lb; |
106 | } |
107 | |
108 | void helper_bndstx64(CPUX86State *env, target_ulong base, target_ulong ptr, |
109 | uint64_t lb, uint64_t ub) |
110 | { |
111 | uintptr_t ra = GETPC(); |
112 | uint64_t bte; |
113 | |
114 | bte = lookup_bte64(env, base, ra); |
115 | cpu_stq_data_ra(env, bte, lb, ra); |
116 | cpu_stq_data_ra(env, bte + 8, ub, ra); |
117 | cpu_stq_data_ra(env, bte + 16, ptr, ra); |
118 | } |
119 | |
120 | void helper_bndstx32(CPUX86State *env, target_ulong base, target_ulong ptr, |
121 | uint64_t lb, uint64_t ub) |
122 | { |
123 | uintptr_t ra = GETPC(); |
124 | uint32_t bte; |
125 | |
126 | bte = lookup_bte32(env, base, ra); |
127 | cpu_stl_data_ra(env, bte, lb, ra); |
128 | cpu_stl_data_ra(env, bte + 4, ub, ra); |
129 | cpu_stl_data_ra(env, bte + 8, ptr, ra); |
130 | } |
131 | |
132 | void helper_bnd_jmp(CPUX86State *env) |
133 | { |
134 | if (!(env->hflags2 & HF2_MPX_PR_MASK)) { |
135 | memset(env->bnd_regs, 0, sizeof(env->bnd_regs)); |
136 | env->hflags &= ~HF_MPX_IU_MASK; |
137 | } |
138 | } |
139 | |