Chromium Code Reviews| 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 |