OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2012 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can | |
4 * be found in the LICENSE file. | |
5 * Copyright 2012, Google Inc. | |
6 */ | |
7 | |
8 #ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H | |
9 #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H | |
10 | |
11 #include <stdint.h> | |
12 #include "native_client/src/trusted/validator_mips/model.h" | |
13 #include "native_client/src/include/portability.h" | |
14 | |
15 | |
16 /* | |
17 * Models the "instruction classes" that the decoder produces. | |
18 */ | |
19 namespace nacl_mips_dec { | |
20 | |
21 /* | |
22 * Used to describe whether an instruction is safe, and if not, what the issue | |
23 * is. Only instructions that MAY_BE_SAFE should be allowed in untrusted code, | |
24 * and even those may be rejected by the validator. | |
Brad Chen
2012/05/04 22:49:50
Why the holes in the enumeration? Why not consecut
petarj
2012/05/08 14:54:19
We used the same values as ARM implementation does
Brad Chen
2012/05/29 16:20:39
What you will probably need to do is watch the sou
| |
25 */ | |
26 enum SafetyLevel { | |
27 // The initial value of uninitialized SafetyLevels -- treat as unsafe. | |
Brad Chen
2012/05/04 22:49:50
Please don't mix comment styles. For C stick with
petarj
2012/05/08 14:54:19
Copied as-is from validator_arm/inst_classes.h
| |
28 UNKNOWN = 0, | |
29 // This instruction is forbidden by our SFI model. | |
30 FORBIDDEN = 4, | |
31 /* | |
32 * This instruction may be safe in untrusted code: in isolation it contains | |
33 * nothing scary, but the validator may overrule this during global analysis. | |
34 */ | |
35 MAY_BE_SAFE = 6 | |
36 }; | |
37 | |
38 | |
39 // Function (op)codes. | |
40 uint32_t const kBitwiseLogicalAnd = 0x24; // b100100. | |
41 | |
42 | |
43 /* | |
44 * Decodes a class of instructions. Does spooky undefined things if handed | |
45 * instructions that don't belong to its class. Who defines which instructions | |
46 * these are? Why, the generated decoder, of course. | |
47 * | |
48 * This is an abstract base class intended to be overridden with the details of | |
49 * particular instruction-classes. | |
50 * | |
51 * ClassDecoders should be stateless, and should provide a no-arg constructor | |
52 * for use by the generated decoder. | |
53 */ | |
54 class ClassDecoder { | |
55 public: | |
56 /* | |
57 * Checks how safe this instruction is, in isolation. | |
58 * This will detect any violation in the Mips spec -- undefined encodings, | |
59 * use of registers that are unpredictable -- and the most basic constraints | |
60 * in our SFI model. Because ClassDecoders are referentially-transparent and | |
61 * cannot touch global state, this will not check things that may vary with | |
62 * ABI version. | |
63 * | |
64 * The most positive result this can return is called MAY_BE_SAFE because it | |
65 * is necessary, but not sufficient: the validator has the final say. | |
66 */ | |
67 virtual SafetyLevel safety(Instruction i) const = 0; | |
Brad Chen
2012/05/04 22:49:50
Mixed case for function/method names. Possible exc
petarj
2012/05/08 14:54:19
Copied as-is from validator_arm/inst_classes.h.
| |
68 | |
69 /* | |
70 * For instructions that perform 'masking', this function will return whether | |
71 * this is true or not for the given instruction. | |
72 * | |
73 * The result is useful only for Arithm3 'and' instruction. | |
74 */ | |
75 virtual bool is_mask(Instruction i, nacl_mips_dec::Register dest, | |
Brad Chen
2012/05/04 22:49:50
Can functions like these could use more const qual
| |
76 nacl_mips_dec::Register mask) const { | |
77 UNREFERENCED_PARAMETER(i); | |
78 UNREFERENCED_PARAMETER(dest); | |
79 UNREFERENCED_PARAMETER(mask); | |
80 return false; | |
81 } | |
82 | |
83 /* | |
84 * The gpr register altered by the instruction. | |
85 */ | |
86 virtual Register dest_gpr_reg(Instruction i) const { | |
87 UNREFERENCED_PARAMETER(i); | |
88 return kRegisterNone; | |
89 } | |
90 | |
91 /* | |
92 * May be used for instr's with immediate operand; like addiu or jal. | |
93 */ | |
94 virtual uint32_t get_imm(Instruction i) const { | |
95 UNREFERENCED_PARAMETER(i); | |
96 return -1; | |
97 } | |
98 | |
99 /* | |
100 * For direct jumps (j, jal, branch instructions). | |
101 */ | |
102 virtual bool is_direct_jump() const { | |
103 return false; | |
104 } | |
105 | |
106 /* | |
107 * For jump and link (jal, jalr, bal). | |
108 */ | |
109 virtual bool is_jal() const { | |
110 return false; | |
111 } | |
112 | |
113 /* | |
114 * For jump register instructions (jr, jalr). | |
115 */ | |
116 virtual bool is_jmp_reg() const { | |
117 return false; | |
118 } | |
119 | |
120 /* | |
121 * For the instructions that are followed by a delay slot. | |
122 */ | |
123 virtual bool has_delay_slot() const { | |
124 return is_direct_jump() || is_jmp_reg(); | |
125 } | |
126 | |
127 /* | |
128 * For load and store instructions. | |
129 */ | |
130 virtual bool is_load_store() const { | |
131 return false; | |
132 } | |
133 | |
134 /* | |
135 * For direct jumps, returning the destination address. | |
136 */ | |
137 virtual uint32_t dest_addr(Instruction i, uint32_t addr) const { | |
138 UNREFERENCED_PARAMETER(i); | |
139 UNREFERENCED_PARAMETER(addr); | |
140 return 0; | |
141 } | |
142 | |
143 /* | |
144 * Used by jump register instructions; returns the register that holds the | |
145 * address to jump to. | |
146 */ | |
147 virtual Register target_reg(Instruction i) const { | |
148 UNREFERENCED_PARAMETER(i); | |
149 return kRegisterNone; | |
150 } | |
151 | |
152 /* | |
153 * Base address register, for load and store instructions. | |
154 */ | |
155 virtual Register base_address_register(Instruction i) const { | |
156 UNREFERENCED_PARAMETER(i); | |
157 return kRegisterNone; | |
158 } | |
159 | |
160 | |
161 protected: | |
162 ClassDecoder() {} | |
163 virtual ~ClassDecoder() {} | |
164 }; | |
165 | |
166 /* | |
167 * Current Mips NaCl halt (jr $zero). | |
168 */ | |
169 class NaClHalt : public ClassDecoder { | |
170 public: | |
171 virtual ~NaClHalt() {} | |
172 virtual SafetyLevel safety(Instruction i) const { | |
173 UNREFERENCED_PARAMETER(i); | |
174 return MAY_BE_SAFE; | |
175 } | |
176 }; | |
177 | |
178 /* | |
179 * Represents an instruction that is forbidden under all circumstances, so we | |
180 * didn't bother decoding it further. | |
181 */ | |
182 class Forbidden : public ClassDecoder { | |
183 public: | |
184 virtual ~Forbidden() {} | |
185 virtual SafetyLevel safety(Instruction i) const { | |
186 UNREFERENCED_PARAMETER(i); | |
187 return FORBIDDEN; | |
188 } | |
189 }; | |
190 | |
191 /* | |
192 * Instructions with 2 registers and an immediate value, where bits 20-16 | |
193 * contain the destination gpr register. | |
194 */ | |
195 class Arithm2 : public ClassDecoder { | |
196 public: | |
197 virtual ~Arithm2() {} | |
198 virtual Register dest_gpr_reg(Instruction i) const { | |
199 return i.reg(20, 16); | |
200 } | |
201 virtual SafetyLevel safety(Instruction i) const { | |
202 UNREFERENCED_PARAMETER(i); | |
203 return MAY_BE_SAFE; | |
204 } | |
205 }; | |
206 | |
207 /* | |
208 * Instruction with 3 registers, with bits 15-11 containing the destination gpr | |
209 * register. | |
210 */ | |
211 class Arithm3 : public ClassDecoder { | |
212 public: | |
213 virtual ~Arithm3() {} | |
214 virtual Register dest_gpr_reg(Instruction i) const { | |
Brad Chen
2012/05/04 22:49:50
I would be grateful if you could think of a better
petarj
2012/05/08 14:54:19
We would gladly replace it with 'instr', sure, jus
| |
215 return i.reg(15, 11); | |
216 } | |
217 virtual SafetyLevel safety(Instruction i) const { | |
218 UNREFERENCED_PARAMETER(i); | |
219 return MAY_BE_SAFE; | |
220 } | |
221 virtual bool is_mask(const Instruction instr, | |
222 const nacl_mips_dec::Register dest, | |
223 const nacl_mips_dec::Register mask) const { | |
224 return ((instr.bits(5, 0) == kBitwiseLogicalAnd) | |
225 && (instr.reg(15, 11) == dest) | |
226 && (instr.reg(25, 21) == dest) | |
227 && (instr.reg(20, 16) == mask)); | |
228 } | |
229 }; | |
230 | |
231 /* | |
232 * Direct jump class, subclassed by Branch and JmpImm. | |
233 */ | |
234 class DirectJump : public ClassDecoder { | |
235 public: | |
236 virtual ~DirectJump() {} | |
237 virtual SafetyLevel safety(Instruction i) const { | |
238 UNREFERENCED_PARAMETER(i); | |
239 return MAY_BE_SAFE; | |
240 } | |
241 virtual bool is_direct_jump() const { | |
242 return true; | |
243 } | |
244 }; | |
245 | |
246 /* | |
247 * Branch instructions. | |
248 */ | |
249 class Branch : public DirectJump { | |
250 public: | |
251 virtual ~Branch() {} | |
252 virtual uint32_t get_imm(Instruction instr) const { | |
253 return instr.bits(15, 0); | |
254 } | |
255 virtual uint32_t dest_addr(Instruction instr, uint32_t addr) const { | |
256 return ((addr + kInstrSize) + ((int16_t)get_imm(instr) << 2)); | |
257 } | |
258 }; | |
259 | |
260 /* | |
261 * Branch and link instructions (bal, bgezal, bltzal, bgezall, bltzall). | |
262 */ | |
263 class BranchAndLink : public Branch { | |
264 public: | |
265 virtual ~BranchAndLink() {} | |
266 virtual bool is_jal() const { | |
267 return true; | |
268 } | |
269 }; | |
270 | |
271 /* | |
272 * Load and store instructions. | |
273 */ | |
274 class AbstractLoadStore : public ClassDecoder { | |
275 public: | |
276 virtual bool is_load_store() const { | |
277 return true; | |
278 } | |
279 virtual ~AbstractLoadStore() {} | |
280 virtual SafetyLevel safety(Instruction i) const { | |
281 UNREFERENCED_PARAMETER(i); | |
282 return MAY_BE_SAFE; | |
283 } | |
284 virtual Register base_address_register(Instruction i) const { | |
285 return i.reg(25, 21); | |
286 } | |
287 }; | |
288 | |
289 /* | |
290 * Store instructions. | |
291 */ | |
292 class Store : public AbstractLoadStore { | |
293 public: | |
294 virtual ~Store() {} | |
295 }; | |
296 | |
297 /* | |
298 * Load instructions, which alter the destination register. | |
299 */ | |
300 class Load : public AbstractLoadStore { | |
301 public: | |
302 virtual ~Load() {} | |
303 virtual Register dest_gpr_reg(Instruction i) const { | |
304 return i.reg(20, 16); | |
305 } | |
306 }; | |
307 | |
308 /* | |
309 * Floating point load and store instructions. | |
310 */ | |
311 class FPLoadStore : public AbstractLoadStore { | |
312 public: | |
313 virtual ~FPLoadStore() {} | |
314 }; | |
315 | |
316 /* | |
317 * Store Conditional class, containing the sc instruction, | |
318 * which might alter the contents of the register which is the 1st operand. | |
319 */ | |
320 class StoreConditional : public Store { | |
321 public: | |
322 virtual ~StoreConditional() {} | |
323 virtual Register dest_gpr_reg(Instruction i) const { | |
324 return i.reg(20, 16); | |
325 } | |
326 }; | |
327 | |
328 /* | |
329 * Direct jumps - j, jal. | |
330 */ | |
331 class JmpImm : public DirectJump { | |
332 public: | |
333 virtual ~JmpImm() {} | |
334 virtual uint32_t get_imm(Instruction instr) const { | |
335 return instr.bits(25, 0); | |
336 } | |
337 virtual uint32_t dest_addr(Instruction instr, uint32_t addr) const { | |
338 return ((addr + kInstrSize) & 0xf0000000) + (get_imm(instr) << 2); | |
339 } | |
340 }; | |
341 | |
342 /* | |
343 * Direct jump and link (jal). | |
344 */ | |
345 class JalImm : public JmpImm { | |
346 public: | |
347 virtual ~JalImm() {} | |
348 virtual bool is_jal() const { | |
349 return true; | |
350 } | |
351 }; | |
352 | |
353 /* | |
354 * Jump register instructions - jr, jalr. | |
355 */ | |
356 class JmpReg : public ClassDecoder { | |
357 public: | |
358 virtual ~JmpReg() {} | |
359 virtual SafetyLevel safety(Instruction i) const { | |
360 UNREFERENCED_PARAMETER(i); | |
361 return MAY_BE_SAFE; | |
362 } | |
363 virtual bool is_jmp_reg() const { | |
364 return true; | |
365 } | |
366 virtual Register target_reg(Instruction i) const { | |
367 return i.reg(25, 21); | |
368 } | |
369 }; | |
370 | |
371 /* | |
372 * Jump and link register - jalr. | |
373 */ | |
374 class JalReg : public JmpReg { | |
375 public: | |
376 virtual ~JalReg() {} | |
377 virtual bool is_jal() const { | |
378 return true; | |
379 } | |
380 virtual Register dest_gpr_reg(Instruction i) const { | |
381 return i.reg(15, 11); | |
382 } | |
383 }; | |
384 | |
385 /* | |
386 * ext and ins instructions. | |
387 */ | |
388 class ExtIns : public ClassDecoder { | |
389 public: | |
390 virtual ~ExtIns() {} | |
391 virtual Register dest_gpr_reg(Instruction i) const { | |
392 return i.reg(20, 16); | |
393 } | |
394 virtual SafetyLevel safety(Instruction i) const { | |
395 UNREFERENCED_PARAMETER(i); | |
396 return MAY_BE_SAFE; | |
397 } | |
398 }; | |
399 /* | |
400 * The instructions that are safe under all circumstances. | |
401 */ | |
402 class Safe : public ClassDecoder { | |
403 public: | |
404 virtual ~Safe() {} | |
405 virtual SafetyLevel safety(Instruction i) const { | |
406 UNREFERENCED_PARAMETER(i); | |
407 return MAY_BE_SAFE; | |
408 } | |
409 }; | |
410 | |
411 class Other : public ClassDecoder { | |
412 public: | |
413 virtual ~Other() {} | |
414 virtual SafetyLevel safety(Instruction i) const { | |
415 UNREFERENCED_PARAMETER(i); | |
416 return FORBIDDEN; | |
417 } | |
418 }; | |
419 | |
420 /* | |
421 * Unknown instructions, treated as forbidden. | |
422 */ | |
423 class Unrecognized : public ClassDecoder { | |
424 public: | |
425 virtual ~Unrecognized() {} | |
426 virtual SafetyLevel safety(Instruction i) const { | |
427 UNREFERENCED_PARAMETER(i); | |
428 return FORBIDDEN; | |
429 } | |
430 }; | |
431 } // namespace | |
432 | |
433 #endif // NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H | |
OLD | NEW |