1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * This file contains common parts of x86-32 and x86-64 internals (inline
9 : * functions and defines).
10 : */
11 :
12 : #ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_RAGEL_VALIDATOR_INTERNAL_H_
13 : #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_RAGEL_VALIDATOR_INTERNAL_H_
14 :
15 : #include "native_client/src/shared/platform/nacl_check.h"
16 : #include "native_client/src/shared/utils/types.h"
17 : #include "native_client/src/trusted/validator_ragel/decoding.h"
18 : #include "native_client/src/trusted/validator_ragel/validator.h"
19 :
20 : /* Maximum set of R-DFA allowable CPUID features. */
21 : extern const NaClCPUFeaturesX86 kValidatorCPUIDFeatures;
22 :
23 : /* Macroses to support CPUID handling. */
24 :
25 : /*
26 : * Main macro: FEATURE parameter here is one of the macroses below, e.g.
27 : * SET_CPU_FEATURE(CPUFeature_AESAVX).
28 : */
29 : #define SET_CPU_FEATURE(FEATURE) \
30 : if (!(FEATURE(kValidatorCPUIDFeatures.data))) { \
31 : instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; \
32 : } \
33 : if (!(FEATURE(cpu_features->data))) { \
34 : instruction_info_collected |= CPUID_UNSUPPORTED_INSTRUCTION; \
35 : }
36 : /*
37 : * Macroses to access induvidual elements of NaClCPUFeaturesX86 structure,
38 : * e.g. CPUFeature_AESAVX(kValidatorCPUIDFeatures.data).
39 : */
40 : #define CPUFeature_3DNOW(FEATURES) FEATURES[NaClCPUFeatureX86_3DNOW]
41 : /*
42 : * AMD documentation claims it's always available if CPUFeature_LM is present,
43 : * But Intel documentation does not even mention it!
44 : * Keep it as 3DNow! instruction.
45 : */
46 : #define CPUFeature_3DPRFTCH(FEATURES) \
47 : (CPUFeature_3DNOW(FEATURES) || CPUFeature_PRE(FEATURES))
48 : #define CPUFeature_AES(FEATURES) FEATURES[NaClCPUFeatureX86_AES]
49 : #define CPUFeature_AESAVX(FEATURES) \
50 : (CPUFeature_AES(FEATURES) && CPUFeature_AVX(FEATURES))
51 : #define CPUFeature_AVX(FEATURES) FEATURES[NaClCPUFeatureX86_AVX]
52 : #define CPUFeature_BMI1(FEATURES) FEATURES[NaClCPUFeatureX86_BMI1]
53 : #define CPUFeature_CLFLUSH(FEATURES) FEATURES[NaClCPUFeatureX86_CLFLUSH]
54 : #define CPUFeature_CLMUL(FEATURES) FEATURES[NaClCPUFeatureX86_CLMUL]
55 : #define CPUFeature_CLMULAVX(FEATURES) \
56 : (CPUFeature_CLMUL(FEATURES) && CPUFeature_AVX(FEATURES))
57 : #define CPUFeature_CMOV(FEATURES) FEATURES[NaClCPUFeatureX86_CMOV]
58 : #define CPUFeature_CMOVx87(FEATURES) \
59 : (CPUFeature_CMOV(FEATURES) && CPUFeature_x87(FEATURES))
60 : #define CPUFeature_CX16(FEATURES) FEATURES[NaClCPUFeatureX86_CX16]
61 : #define CPUFeature_CX8(FEATURES) FEATURES[NaClCPUFeatureX86_CX8]
62 : #define CPUFeature_E3DNOW(FEATURES) FEATURES[NaClCPUFeatureX86_E3DNOW]
63 : #define CPUFeature_EMMX(FEATURES) FEATURES[NaClCPUFeatureX86_EMMX]
64 : #define CPUFeature_EMMXSSE(FEATURES) \
65 : (CPUFeature_EMMX(FEATURES) || CPUFeature_SSE(FEATURES))
66 : #define CPUFeature_F16C(FEATURES) FEATURES[NaClCPUFeatureX86_F16C]
67 : #define CPUFeature_FMA(FEATURES) FEATURES[NaClCPUFeatureX86_FMA]
68 : #define CPUFeature_FMA4(FEATURES) FEATURES[NaClCPUFeatureX86_FMA4]
69 : #define CPUFeature_FXSR(FEATURES) FEATURES[NaClCPUFeatureX86_FXSR]
70 : #define CPUFeature_LAHF(FEATURES) FEATURES[NaClCPUFeatureX86_LAHF]
71 : #define CPUFeature_LM(FEATURES) FEATURES[NaClCPUFeatureX86_LM]
72 : #define CPUFeature_LWP(FEATURES) FEATURES[NaClCPUFeatureX86_LWP]
73 : /*
74 : * We allow lzcnt unconditionally
75 : * See http://code.google.com/p/nativeclient/issues/detail?id=2869
76 : */
77 : #define CPUFeature_LZCNT(FEATURES) TRUE
78 : #define CPUFeature_MMX(FEATURES) FEATURES[NaClCPUFeatureX86_MMX]
79 : #define CPUFeature_MON(FEATURES) FEATURES[NaClCPUFeatureX86_MON]
80 : #define CPUFeature_MOVBE(FEATURES) FEATURES[NaClCPUFeatureX86_MOVBE]
81 : #define CPUFeature_OSXSAVE(FEATURES) FEATURES[NaClCPUFeatureX86_OSXSAVE]
82 : #define CPUFeature_POPCNT(FEATURES) FEATURES[NaClCPUFeatureX86_POPCNT]
83 : #define CPUFeature_PRE(FEATURES) FEATURES[NaClCPUFeatureX86_PRE]
84 : #define CPUFeature_SSE(FEATURES) FEATURES[NaClCPUFeatureX86_SSE]
85 : #define CPUFeature_SSE2(FEATURES) FEATURES[NaClCPUFeatureX86_SSE2]
86 : #define CPUFeature_SSE3(FEATURES) FEATURES[NaClCPUFeatureX86_SSE3]
87 : #define CPUFeature_SSE41(FEATURES) FEATURES[NaClCPUFeatureX86_SSE41]
88 : #define CPUFeature_SSE42(FEATURES) FEATURES[NaClCPUFeatureX86_SSE42]
89 : #define CPUFeature_SSE4A(FEATURES) FEATURES[NaClCPUFeatureX86_SSE4A]
90 : #define CPUFeature_SSSE3(FEATURES) FEATURES[NaClCPUFeatureX86_SSSE3]
91 : #define CPUFeature_TBM(FEATURES) FEATURES[NaClCPUFeatureX86_TBM]
92 : #define CPUFeature_TSC(FEATURES) FEATURES[NaClCPUFeatureX86_TSC]
93 : /*
94 : * We allow tzcnt unconditionally
95 : * See http://code.google.com/p/nativeclient/issues/detail?id=2869
96 : */
97 : #define CPUFeature_TZCNT(FEATURES) TRUE
98 : #define CPUFeature_x87(FEATURES) FEATURES[NaClCPUFeatureX86_x87]
99 : #define CPUFeature_XOP(FEATURES) FEATURES[NaClCPUFeatureX86_XOP]
100 :
101 : /* Remember some information about instruction for further processing. */
102 : #define GET_REX_PREFIX() rex_prefix
103 : #define SET_REX_PREFIX(PREFIX_BYTE) rex_prefix = (PREFIX_BYTE)
104 : #define GET_VEX_PREFIX2() vex_prefix2
105 : #define SET_VEX_PREFIX2(PREFIX_BYTE) vex_prefix2 = (PREFIX_BYTE)
106 : #define GET_VEX_PREFIX3() vex_prefix3
107 : #define SET_VEX_PREFIX3(PREFIX_BYTE) vex_prefix3 = (PREFIX_BYTE)
108 : #define SET_MODRM_BASE(REG_NUMBER) base = (REG_NUMBER)
109 : #define SET_MODRM_INDEX(REG_NUMBER) index = (REG_NUMBER)
110 :
111 : /* Ignore this information for now. */
112 : #define SET_DATA16_PREFIX(STATUS)
113 : #define SET_REPZ_PREFIX(STATUS)
114 : #define SET_REPNZ_PREFIX(STATUS)
115 : #define SET_MODRM_SCALE(VALUE)
116 : #define SET_DISPLACEMENT_POINTER(POINTER)
117 : #define SET_IMMEDIATE_POINTER(POINTER)
118 : #define SET_SECOND_IMMEDIATE_POINTER(POINTER)
119 :
120 : /*
121 : * Collect information about anyfields (offsets and immediates).
122 : * Note: we use += below instead of |=. This means two immediate fields will
123 : * be treated as one. It's not important for safety.
124 : */
125 : #define SET_DISPLACEMENT_FORMAT(FORMAT) SET_DISPLACEMENT_FORMAT_##FORMAT
126 : #define SET_DISPLACEMENT_FORMAT_DISPNONE
127 : #define SET_DISPLACEMENT_FORMAT_DISP8 \
128 : (instruction_info_collected += DISPLACEMENT_8BIT)
129 : #define SET_DISPLACEMENT_FORMAT_DISP32 \
130 : (instruction_info_collected += DISPLACEMENT_32BIT)
131 : #define SET_IMMEDIATE_FORMAT(FORMAT) SET_IMMEDIATE_FORMAT_##FORMAT
132 : /* imm2 field is a flag, not accumulator, like other immediates */
133 : #define SET_IMMEDIATE_FORMAT_IMM2 \
134 : (instruction_info_collected |= IMMEDIATE_2BIT)
135 : #define SET_IMMEDIATE_FORMAT_IMM8 \
136 : (instruction_info_collected += IMMEDIATE_8BIT)
137 : #define SET_IMMEDIATE_FORMAT_IMM16 \
138 : (instruction_info_collected += IMMEDIATE_16BIT)
139 : #define SET_IMMEDIATE_FORMAT_IMM32 \
140 : (instruction_info_collected += IMMEDIATE_32BIT)
141 : #define SET_IMMEDIATE_FORMAT_IMM64 \
142 : (instruction_info_collected += IMMEDIATE_64BIT)
143 : #define SET_SECOND_IMMEDIATE_FORMAT(FORMAT) \
144 : SET_SECOND_IMMEDIATE_FORMAT_##FORMAT
145 : #define SET_SECOND_IMMEDIATE_FORMAT_IMM8 \
146 : (instruction_info_collected += SECOND_IMMEDIATE_8BIT)
147 : #define SET_SECOND_IMMEDIATE_FORMAT_IMM16 \
148 : (instruction_info_collected += SECOND_IMMEDIATE_16BIT)
149 :
150 : /*
151 : * Mark the destination of a jump instruction and make an early validity check:
152 : * jump target outside of given code region must be aligned.
153 : *
154 : * Returns TRUE iff the jump passes the early validity check.
155 : */
156 : static FORCEINLINE int MarkJumpTarget(size_t jump_dest,
157 : bitmap_word *jump_dests,
158 2 : size_t size) {
159 2 : if ((jump_dest & kBundleMask) == 0) {
160 2 : return TRUE;
161 : }
162 2 : if (jump_dest >= size) {
163 2 : return FALSE;
164 : }
165 2 : BitmapSetBit(jump_dests, jump_dest);
166 2 : return TRUE;
167 2 : }
168 :
169 : /*
170 : * Mark the given address as valid jump target address.
171 : */
172 : static FORCEINLINE void MarkValidJumpTarget(size_t address,
173 2 : bitmap_word *valid_targets) {
174 2 : BitmapSetBit(valid_targets, address);
175 2 : }
176 :
177 : /*
178 : * Mark the given address as invalid jump target address (that is: unmark it).
179 : */
180 : static FORCEINLINE void UnmarkValidJumpTarget(size_t address,
181 1 : bitmap_word *valid_targets) {
182 1 : BitmapClearBit(valid_targets, address);
183 1 : }
184 :
185 : /*
186 : * Mark the given addresses as invalid jump target addresses (that is: unmark
187 : * them).
188 : */
189 : static FORCEINLINE void UnmarkValidJumpTargets(size_t address,
190 : size_t bytes,
191 1 : bitmap_word *valid_targets) {
192 1 : BitmapClearBits(valid_targets, address, bytes);
193 1 : }
194 :
195 : /*
196 : * Compare valid_targets and jump_dests and call callback for any address in
197 : * jump_dests which is not present in valid_targets.
198 : */
199 : static INLINE Bool ProcessInvalidJumpTargets(
200 : const uint8_t codeblock[],
201 : size_t size,
202 : bitmap_word *valid_targets,
203 : bitmap_word *jump_dests,
204 : ValidationCallbackFunc user_callback,
205 2 : void *callback_data) {
206 2 : size_t elements = (size + NACL_HOST_WORDSIZE - 1) / NACL_HOST_WORDSIZE;
207 : size_t i, j;
208 2 : Bool result = TRUE;
209 :
210 2 : for (i = 0; i < elements; i++) {
211 2 : bitmap_word jump_dest_mask = jump_dests[i];
212 2 : bitmap_word valid_target_mask = valid_targets[i];
213 2 : if ((jump_dest_mask & ~valid_target_mask) != 0) {
214 2 : for (j = i * NACL_HOST_WORDSIZE; j < (i + 1) * NACL_HOST_WORDSIZE; j++)
215 : if (BitmapIsBitSet(jump_dests, j) &&
216 2 : !BitmapIsBitSet(valid_targets, j)) {
217 : result &= user_callback(codeblock + j,
218 : codeblock + j,
219 : BAD_JUMP_TARGET,
220 2 : callback_data);
221 : }
222 2 : }
223 2 : }
224 :
225 2 : return result;
226 2 : }
227 :
228 :
229 : /*
230 : * Process rel8_operand. Note: rip points to the beginning of the next
231 : * instruction here and x86 encoding guarantees rel8 field is the last one
232 : * in a current instruction.
233 : */
234 : static FORCEINLINE void Rel8Operand(const uint8_t *rip,
235 : const uint8_t codeblock[],
236 : bitmap_word *jump_dests,
237 : size_t jumpdests_size,
238 2 : uint32_t *instruction_info_collected) {
239 2 : int8_t offset = rip[-1];
240 2 : size_t jump_dest = offset + (rip - codeblock);
241 :
242 2 : if (MarkJumpTarget(jump_dest, jump_dests, jumpdests_size))
243 2 : *instruction_info_collected |= RELATIVE_8BIT;
244 2 : else
245 2 : *instruction_info_collected |= RELATIVE_8BIT | DIRECT_JUMP_OUT_OF_RANGE;
246 2 : }
247 :
248 : /*
249 : * Process rel32_operand. Note: rip points to the beginning of the next
250 : * instruction here and x86 encoding guarantees rel32 field is the last one
251 : * in a current instruction.
252 : */
253 : static FORCEINLINE void Rel32Operand(const uint8_t *rip,
254 : const uint8_t codeblock[],
255 : bitmap_word *jump_dests,
256 : size_t jumpdests_size,
257 2 : uint32_t *instruction_info_collected) {
258 : int32_t offset =
259 2 : rip[-4] + 256U * (rip[-3] + 256U * (rip[-2] + 256U * (rip[-1])));
260 2 : size_t jump_dest = offset + (rip - codeblock);
261 :
262 2 : if (MarkJumpTarget(jump_dest, jump_dests, jumpdests_size))
263 2 : *instruction_info_collected |= RELATIVE_32BIT;
264 2 : else
265 2 : *instruction_info_collected |= RELATIVE_32BIT | DIRECT_JUMP_OUT_OF_RANGE;
266 2 : }
267 :
268 : #endif /* NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_RAGEL_VALIDATOR_INTERNAL_H_ */
|