Chromium Code Reviews| Index: src/trusted/validator_mips/inst_classes.h |
| diff --git a/src/trusted/validator_mips/inst_classes.h b/src/trusted/validator_mips/inst_classes.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..27dd8cc971945b5fea8b688ba1c1c38c77b2ef76 |
| --- /dev/null |
| +++ b/src/trusted/validator_mips/inst_classes.h |
| @@ -0,0 +1,433 @@ |
| +/* |
| + * Copyright 2012 The Native Client Authors. All rights reserved. |
| + * Use of this source code is governed by a BSD-style license that can |
| + * be found in the LICENSE file. |
| + * Copyright 2012, Google Inc. |
| + */ |
| + |
| +#ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H |
| +#define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H |
| + |
| +#include <stdint.h> |
| +#include "native_client/src/trusted/validator_mips/model.h" |
| +#include "native_client/src/include/portability.h" |
| + |
| + |
| +/* |
| + * Models the "instruction classes" that the decoder produces. |
| + */ |
| +namespace nacl_mips_dec { |
| + |
| +/* |
| + * Used to describe whether an instruction is safe, and if not, what the issue |
| + * is. Only instructions that MAY_BE_SAFE should be allowed in untrusted code, |
| + * 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
|
| + */ |
| +enum SafetyLevel { |
| + // 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
|
| + UNKNOWN = 0, |
| + // This instruction is forbidden by our SFI model. |
| + FORBIDDEN = 4, |
| + /* |
| + * This instruction may be safe in untrusted code: in isolation it contains |
| + * nothing scary, but the validator may overrule this during global analysis. |
| + */ |
| + MAY_BE_SAFE = 6 |
| +}; |
| + |
| + |
| +// Function (op)codes. |
| +uint32_t const kBitwiseLogicalAnd = 0x24; // b100100. |
| + |
| + |
| +/* |
| + * Decodes a class of instructions. Does spooky undefined things if handed |
| + * instructions that don't belong to its class. Who defines which instructions |
| + * these are? Why, the generated decoder, of course. |
| + * |
| + * This is an abstract base class intended to be overridden with the details of |
| + * particular instruction-classes. |
| + * |
| + * ClassDecoders should be stateless, and should provide a no-arg constructor |
| + * for use by the generated decoder. |
| + */ |
| +class ClassDecoder { |
| + public: |
| + /* |
| + * Checks how safe this instruction is, in isolation. |
| + * This will detect any violation in the Mips spec -- undefined encodings, |
| + * use of registers that are unpredictable -- and the most basic constraints |
| + * in our SFI model. Because ClassDecoders are referentially-transparent and |
| + * cannot touch global state, this will not check things that may vary with |
| + * ABI version. |
| + * |
| + * The most positive result this can return is called MAY_BE_SAFE because it |
| + * is necessary, but not sufficient: the validator has the final say. |
| + */ |
| + 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.
|
| + |
| + /* |
| + * For instructions that perform 'masking', this function will return whether |
| + * this is true or not for the given instruction. |
| + * |
| + * The result is useful only for Arithm3 'and' instruction. |
| + */ |
| + 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
|
| + nacl_mips_dec::Register mask) const { |
| + UNREFERENCED_PARAMETER(i); |
| + UNREFERENCED_PARAMETER(dest); |
| + UNREFERENCED_PARAMETER(mask); |
| + return false; |
| + } |
| + |
| + /* |
| + * The gpr register altered by the instruction. |
| + */ |
| + virtual Register dest_gpr_reg(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return kRegisterNone; |
| + } |
| + |
| + /* |
| + * May be used for instr's with immediate operand; like addiu or jal. |
| + */ |
| + virtual uint32_t get_imm(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return -1; |
| + } |
| + |
| + /* |
| + * For direct jumps (j, jal, branch instructions). |
| + */ |
| + virtual bool is_direct_jump() const { |
| + return false; |
| + } |
| + |
| + /* |
| + * For jump and link (jal, jalr, bal). |
| + */ |
| + virtual bool is_jal() const { |
| + return false; |
| + } |
| + |
| + /* |
| + * For jump register instructions (jr, jalr). |
| + */ |
| + virtual bool is_jmp_reg() const { |
| + return false; |
| + } |
| + |
| + /* |
| + * For the instructions that are followed by a delay slot. |
| + */ |
| + virtual bool has_delay_slot() const { |
| + return is_direct_jump() || is_jmp_reg(); |
| + } |
| + |
| + /* |
| + * For load and store instructions. |
| + */ |
| + virtual bool is_load_store() const { |
| + return false; |
| + } |
| + |
| + /* |
| + * For direct jumps, returning the destination address. |
| + */ |
| + virtual uint32_t dest_addr(Instruction i, uint32_t addr) const { |
| + UNREFERENCED_PARAMETER(i); |
| + UNREFERENCED_PARAMETER(addr); |
| + return 0; |
| + } |
| + |
| + /* |
| + * Used by jump register instructions; returns the register that holds the |
| + * address to jump to. |
| + */ |
| + virtual Register target_reg(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return kRegisterNone; |
| + } |
| + |
| + /* |
| + * Base address register, for load and store instructions. |
| + */ |
| + virtual Register base_address_register(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return kRegisterNone; |
| + } |
| + |
| + |
| + protected: |
| + ClassDecoder() {} |
| + virtual ~ClassDecoder() {} |
| +}; |
| + |
| +/* |
| + * Current Mips NaCl halt (jr $zero). |
| + */ |
| +class NaClHalt : public ClassDecoder { |
| + public: |
| + virtual ~NaClHalt() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| +}; |
| + |
| +/* |
| + * Represents an instruction that is forbidden under all circumstances, so we |
| + * didn't bother decoding it further. |
| + */ |
| +class Forbidden : public ClassDecoder { |
| + public: |
| + virtual ~Forbidden() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return FORBIDDEN; |
| + } |
| +}; |
| + |
| +/* |
| + * Instructions with 2 registers and an immediate value, where bits 20-16 |
| + * contain the destination gpr register. |
| + */ |
| +class Arithm2 : public ClassDecoder { |
| + public: |
| + virtual ~Arithm2() {} |
| + virtual Register dest_gpr_reg(Instruction i) const { |
| + return i.reg(20, 16); |
| + } |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| +}; |
| + |
| +/* |
| + * Instruction with 3 registers, with bits 15-11 containing the destination gpr |
| + * register. |
| + */ |
| +class Arithm3 : public ClassDecoder { |
| + public: |
| + virtual ~Arithm3() {} |
| + 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
|
| + return i.reg(15, 11); |
| + } |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| + virtual bool is_mask(const Instruction instr, |
| + const nacl_mips_dec::Register dest, |
| + const nacl_mips_dec::Register mask) const { |
| + return ((instr.bits(5, 0) == kBitwiseLogicalAnd) |
| + && (instr.reg(15, 11) == dest) |
| + && (instr.reg(25, 21) == dest) |
| + && (instr.reg(20, 16) == mask)); |
| + } |
| +}; |
| + |
| +/* |
| + * Direct jump class, subclassed by Branch and JmpImm. |
| + */ |
| +class DirectJump : public ClassDecoder { |
| + public: |
| + virtual ~DirectJump() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| + virtual bool is_direct_jump() const { |
| + return true; |
| + } |
| +}; |
| + |
| +/* |
| + * Branch instructions. |
| + */ |
| +class Branch : public DirectJump { |
| + public: |
| + virtual ~Branch() {} |
| + virtual uint32_t get_imm(Instruction instr) const { |
| + return instr.bits(15, 0); |
| + } |
| + virtual uint32_t dest_addr(Instruction instr, uint32_t addr) const { |
| + return ((addr + kInstrSize) + ((int16_t)get_imm(instr) << 2)); |
| + } |
| +}; |
| + |
| +/* |
| + * Branch and link instructions (bal, bgezal, bltzal, bgezall, bltzall). |
| + */ |
| +class BranchAndLink : public Branch { |
| + public: |
| + virtual ~BranchAndLink() {} |
| + virtual bool is_jal() const { |
| + return true; |
| + } |
| +}; |
| + |
| +/* |
| + * Load and store instructions. |
| + */ |
| +class AbstractLoadStore : public ClassDecoder { |
| + public: |
| + virtual bool is_load_store() const { |
| + return true; |
| + } |
| + virtual ~AbstractLoadStore() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| + virtual Register base_address_register(Instruction i) const { |
| + return i.reg(25, 21); |
| + } |
| +}; |
| + |
| +/* |
| + * Store instructions. |
| + */ |
| +class Store : public AbstractLoadStore { |
| + public: |
| + virtual ~Store() {} |
| +}; |
| + |
| +/* |
| + * Load instructions, which alter the destination register. |
| + */ |
| +class Load : public AbstractLoadStore { |
| + public: |
| + virtual ~Load() {} |
| + virtual Register dest_gpr_reg(Instruction i) const { |
| + return i.reg(20, 16); |
| + } |
| +}; |
| + |
| +/* |
| + * Floating point load and store instructions. |
| + */ |
| +class FPLoadStore : public AbstractLoadStore { |
| + public: |
| + virtual ~FPLoadStore() {} |
| +}; |
| + |
| +/* |
| + * Store Conditional class, containing the sc instruction, |
| + * which might alter the contents of the register which is the 1st operand. |
| + */ |
| +class StoreConditional : public Store { |
| + public: |
| + virtual ~StoreConditional() {} |
| + virtual Register dest_gpr_reg(Instruction i) const { |
| + return i.reg(20, 16); |
| + } |
| +}; |
| + |
| +/* |
| + * Direct jumps - j, jal. |
| + */ |
| +class JmpImm : public DirectJump { |
| + public: |
| + virtual ~JmpImm() {} |
| + virtual uint32_t get_imm(Instruction instr) const { |
| + return instr.bits(25, 0); |
| + } |
| + virtual uint32_t dest_addr(Instruction instr, uint32_t addr) const { |
| + return ((addr + kInstrSize) & 0xf0000000) + (get_imm(instr) << 2); |
| + } |
| +}; |
| + |
| +/* |
| + * Direct jump and link (jal). |
| + */ |
| +class JalImm : public JmpImm { |
| + public: |
| + virtual ~JalImm() {} |
| + virtual bool is_jal() const { |
| + return true; |
| + } |
| +}; |
| + |
| +/* |
| + * Jump register instructions - jr, jalr. |
| + */ |
| +class JmpReg : public ClassDecoder { |
| + public: |
| + virtual ~JmpReg() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| + virtual bool is_jmp_reg() const { |
| + return true; |
| + } |
| + virtual Register target_reg(Instruction i) const { |
| + return i.reg(25, 21); |
| + } |
| +}; |
| + |
| +/* |
| + * Jump and link register - jalr. |
| + */ |
| +class JalReg : public JmpReg { |
| + public: |
| + virtual ~JalReg() {} |
| + virtual bool is_jal() const { |
| + return true; |
| + } |
| + virtual Register dest_gpr_reg(Instruction i) const { |
| + return i.reg(15, 11); |
| + } |
| +}; |
| + |
| +/* |
| + * ext and ins instructions. |
| + */ |
| +class ExtIns : public ClassDecoder { |
| + public: |
| + virtual ~ExtIns() {} |
| + virtual Register dest_gpr_reg(Instruction i) const { |
| + return i.reg(20, 16); |
| + } |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| +}; |
| +/* |
| + * The instructions that are safe under all circumstances. |
| + */ |
| +class Safe : public ClassDecoder { |
| + public: |
| + virtual ~Safe() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return MAY_BE_SAFE; |
| + } |
| +}; |
| + |
| +class Other : public ClassDecoder { |
| + public: |
| + virtual ~Other() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return FORBIDDEN; |
| + } |
| +}; |
| + |
| +/* |
| + * Unknown instructions, treated as forbidden. |
| + */ |
| +class Unrecognized : public ClassDecoder { |
| + public: |
| + virtual ~Unrecognized() {} |
| + virtual SafetyLevel safety(Instruction i) const { |
| + UNREFERENCED_PARAMETER(i); |
| + return FORBIDDEN; |
| + } |
| +}; |
| +} // namespace |
| + |
| +#endif // NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H |