Index: src/trusted/validator_arm/inst_classes.h |
diff --git a/src/trusted/validator_arm/inst_classes.h b/src/trusted/validator_arm/inst_classes.h |
index ade271e30e3be387e161da49efd90bbe41b7de29..1329a80b2cffe939dd64b8e632d9576195128921 100644 |
--- a/src/trusted/validator_arm/inst_classes.h |
+++ b/src/trusted/validator_arm/inst_classes.h |
@@ -10,6 +10,8 @@ |
#include <stdint.h> |
#include "native_client/src/trusted/validator_arm/model.h" |
#include "native_client/src/include/portability.h" |
+// TODO(mrm) Remove this with debugging lines |
bsy
2011/09/21 22:32:17
mrm
|
+#include <stdio.h> |
/* |
* Models the "instruction classes" that the decoder produces. |
@@ -17,6 +19,44 @@ |
namespace nacl_arm_dec { |
/* |
+ * Describes whether an operation is safe to have during an IT. |
+ */ |
+enum ITSafety { |
+// Safe to use in an IT block |
+ALWAYS, |
+// Unsafe to use in an IT block |
+NEVER, |
+// Can only go at the end of an IT block |
+END |
+}; |
+ |
+/* |
+ * Describes what mode an instruction governed under an IT is in. |
+ * THEN means condition must match, ELSE means condition must not match, |
+ * NONE means this is the end of IT control flow. |
+ */ |
+enum ITMode { |
+// No condition. There should be no Thens or Elses after this |
+NONE = 0, |
+// Matches condition |
+THEN = 1, |
+// Does not match condition |
+ELSE = 2 |
+}; |
+ |
+/* |
+ * Used to store the full it conditional. This should fit in a byte, and so is |
+ * used instead of an array. It is a bitpacked size 4 array of 2 bit values. |
+ */ |
+typedef uint8_t ITCond; |
+inline ITMode it_select(uint8_t index, ITCond cond) { |
+ return (ITMode)((cond >> (2 * index)) & 0x3); |
+} |
Karl
2011/09/19 19:56:05
Blank line?
|
+inline ITCond it_set(uint8_t index, ITMode mode, ITCond cond) { |
Karl
2011/09/19 19:56:05
Comment describing function?
|
+ return (mode << (2 * index)) | (cond & (~(0x3 << (2 * index)))); |
bsy
2011/09/21 22:32:17
nits:
CHECK(0 <= index); CHECK(index < 4)???
the
jasonwkim
2011/09/26 21:35:52
Done
Don't want to add in dependency to NACL_LOG h
|
+} |
+ |
+/* |
* 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. |
@@ -176,6 +216,18 @@ class ClassDecoder { |
} |
/* |
+ * Checks that an instruction sets a certain pattern of bits in all its |
+ * (non-flag) result registers. The mask should include 1s in the positions |
+ * that should be set. Unlike clears_bits, which may clear a superset of these |
+ * bits, sets_bits must set PRECISELY the bits in mask. |
+ */ |
+ virtual bool sets_bits(Instruction i, uint32_t mask) const { |
+ UNREFERENCED_PARAMETER(i); |
+ UNREFERENCED_PARAMETER(mask); |
+ return false; |
+ } |
+ |
+ /* |
* Checks that an instruction clears a certain pattern of bits in all its |
* (non-flag) result registers. The mask should include 1s in the positions |
* that should be cleared. |
@@ -202,12 +254,52 @@ class ClassDecoder { |
return false; |
} |
+ /* |
+ * Generates the appropriate it condition set for this instruction. |
+ * All entries after a NONE is hit should be zero. |
+ * Default return is that no IT is in effect. |
+ * There are exactly 4 entries, encoded as a bitpacked 2-bit element array. |
+ */ |
+ virtual ITCond it_sequence(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return 0; |
+ } |
+ |
+ /* |
+ * Determines under what conditions an instruction is safe to have in an IT |
+ * block for CPU sanity. Usually, most instructions are. |
+ */ |
+ virtual ITSafety it_safe(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return ALWAYS; |
bsy
2011/09/21 22:32:17
this seems like an unsafe default. if a subclass
|
+ } |
+ |
+ /* |
+ * Calculate the condition code. This used to be done by Instruction, |
+ * but Thumb has some special cases, so we hook here for potential override. |
+ */ |
+ virtual Instruction::Condition condition(Instruction i) const { |
+ return i.condition(); |
+ } |
+ |
protected: |
ClassDecoder() {} |
virtual ~ClassDecoder() {} |
}; |
/* |
+ * Base class for thumb decoders, has different default behavior for conditions |
+ */ |
+class ClassDecoderT : public ClassDecoder { |
+ public: |
+ virtual ~ClassDecoderT() {} |
+ virtual Instruction::Condition condition(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return Instruction::UNCONDITIONAL; |
+ } |
+}; |
+ |
+/* |
* Represents an instruction that is forbidden under all circumstances, so we |
* didn't bother decoding it further. |
*/ |
@@ -336,6 +428,14 @@ class Breakpoint : public Roadblock { |
virtual bool is_literal_pool_head(Instruction i) const; |
}; |
+class ThumbBreakpoint : public Breakpoint { |
+ public: |
+ virtual ~ThumbBreakpoint() {} |
+ |
+ virtual bool is_literal_pool_head(Instruction i) const; |
+}; |
+ |
+ |
/* |
* Models the most common class of data processing instructions. We use this |
* for any operation that |
@@ -768,6 +868,505 @@ class Branch : public ClassDecoder { |
virtual int32_t branch_target_offset(Instruction i) const; |
}; |
+/* Thumb Classes */ |
Karl
2011/09/19 19:56:05
Thumb2?
jasonwkim
2011/09/26 21:35:52
no, thumb2 adds some 32bit insts to thumb. This wo
|
+ |
+class Def3 : public ClassDecoderT { |
+ public: |
+ virtual ~Def3() {} |
+ |
+ virtual SafetyLevel safety(Instruction i) const; |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class Def8_10 : public ClassDecoderT { |
+ public: |
+ virtual ~Def8_10() {} |
+ |
+ virtual SafetyLevel safety(Instruction i) const; |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class MemOpThumb : public ClassDecoderT { |
+ public: |
+ virtual ~MemOpThumb() {} |
+ |
+ virtual SafetyLevel safety(Instruction i) const; |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ |
+ virtual Register base_address_register(Instruction i) const; |
+}; |
+ |
+class MemOpThumbLoad : public MemOpThumb { |
+ public: |
+ virtual ~MemOpThumbLoad() {} |
+ |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class MemOpThumbStore : public MemOpThumb { |
+ public: |
+ virtual ~MemOpThumbStore() {} |
+ |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+}; |
+ |
+class SPMod : public ClassDecoderT { |
+ public: |
+ virtual ~SPMod() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterStack; |
+ } |
+}; |
+ |
+// mrm BiC3, OrMask3, Mask3 are dummies atm, and could be replaced by |
+// Def3, its only potential purpose is to allow registerwise |
+// bitmasking, which is not a current feature. |
+class BiC3 : public Def3 { |
+ public: |
+ virtual ~BiC3() {} |
+}; |
+ |
+class Mask3 : public Def3 { |
+ public: |
+ virtual ~Mask3() {} |
+}; |
+ |
+class OrMask3 : public Def3 { |
+ public: |
+ virtual ~OrMask3() {} |
+}; |
+ |
+class Cmp : public ClassDecoderT { |
+ public : |
+ virtual ~Cmp() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ // mrm may want logic for cmp sandboxing, but not atm |
+ // This would be a superclass for that, not the target class |
+}; |
+ |
+class CmpBrZ : public ClassDecoderT { |
+ public: |
+ virtual ~CmpBrZ() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterPc; |
+ } |
+ virtual bool is_relative_branch(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+ virtual ITSafety it_safe(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return NEVER; |
+ } |
+ virtual int32_t branch_target_offset(Instruction i) const; |
+}; |
+ |
+class PushMult : public ClassDecoderT { |
+ public: |
+ virtual ~PushMult() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterStack; |
+ } |
+ virtual Register base_address_register(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterStack; |
+ } |
+ virtual RegisterList immediate_addressing_defs(Instruction i) const { |
+ return base_address_register(i); |
+ } |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+}; |
+ |
+class PopMult : public PushMult { |
+ public: |
+ virtual ~PopMult() {} |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class BranchT : public ClassDecoder { |
+ public: |
+ virtual ~BranchT() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterPc; |
+ } |
+ virtual bool is_relative_branch(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+ virtual ITSafety it_safe(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return END; |
+ } |
+}; |
+ |
+class BranchTCond : public BranchT { |
+ public: |
+ virtual ~BranchTCond() {} |
+ virtual SafetyLevel safety(Instruction i) const; |
+ virtual ITSafety it_safe(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return NEVER; |
+ } |
+}; |
+ |
+class BranchT1 : public BranchTCond { |
+ virtual int32_t branch_target_offset(Instruction i) const; |
+ virtual Instruction::Condition condition(Instruction i) const; |
+}; |
+ |
+class BranchT2 : public BranchT { |
+ public: |
+ virtual ~BranchT2() {} |
+ virtual int32_t branch_target_offset(Instruction i) const; |
+}; |
+ |
+class BranchT3 : public BranchTCond { |
+ public: |
+ virtual ~BranchT3() {} |
+ virtual int32_t branch_target_offset(Instruction i) const; |
+ virtual Instruction::Condition condition(Instruction i) const; |
+}; |
+ |
+class BranchT4 : public BranchT { |
+ public: |
+ virtual ~BranchT4() {} |
+ virtual int32_t branch_target_offset(Instruction i) const; |
+}; |
+ |
+class STMT1 : public ClassDecoderT { |
+ public: |
+ virtual ~STMT1() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList immediate_addressing_defs(Instruction i) const; |
+ virtual RegisterList defs(Instruction i) const; |
+ virtual Register base_address_register(Instruction i) const; |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+}; |
+ |
+class LDMT1 : public STMT1 { |
+ public: |
+ virtual ~LDMT1() {} |
+ virtual RegisterList defs(Instruction i) const; |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return false; |
+ } |
+}; |
+ |
+class LDRLitT1 : public ClassDecoderT { |
+ public: |
+ virtual ~LDRLitT1() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class ADRT1 : public ClassDecoderT { |
+ public: |
+ virtual ~ADRT1() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class MemOpSPThumbStore : public ClassDecoderT { |
+ public: |
+ virtual ~MemOpSPThumbStore() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ virtual Register base_address_register(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterStack; |
+ } |
+}; |
+ |
+class MemOpSPThumbLoad : public ClassDecoderT { |
+ public: |
+ virtual ~MemOpSPThumbLoad() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const; |
+ virtual Register base_address_register(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterStack; |
+ } |
+}; |
+ |
+class DPMImm : public ClassDecoderT { |
+ public: |
+ virtual ~DPMImm() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class BicModImmT : public DPMImm { |
+ public: |
+ virtual ~BicModImmT() {} |
+ virtual bool clears_bits(Instruction i, uint32_t mask) const; |
+}; |
+ |
+class OrrModImmT : public DPMImm { |
+ public: |
+ virtual ~OrrModImmT() {} |
+ virtual bool sets_bits(Instruction i, uint32_t mask) const; |
+}; |
+ |
+class MovT : public Def3 { |
+ public: |
+ virtual ~MovT() {} |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class BXT : public ClassDecoderT { |
+ public: |
+ virtual ~BXT() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterPc; |
+ } |
+ Register branch_target_register(Instruction i) const; |
+ virtual ITSafety it_safe(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return END; |
+ } |
+}; |
+ |
+class BLXT : public BXT { |
+ public: |
+ virtual ~BLXT() {} |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterPc + kRegisterLink; |
+ } |
+}; |
+ |
+class BLT : public ClassDecoderT { |
+ public: |
+ virtual ~BLT() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterPc + kRegisterLink; |
+ } |
+ virtual bool is_relative_branch(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+ virtual int32_t branch_target_offset(Instruction i) const; |
+ virtual ITSafety it_safe(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return END; |
+ } |
+}; |
+ |
+class IT : public ClassDecoderT { |
+ public: |
+ virtual ~IT() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual ITSafety it_safe(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return NEVER; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ virtual Instruction::Condition condition(Instruction i) const; |
+ virtual ITCond it_sequence(Instruction i) const; |
+}; |
+ |
+class STMTD : public ClassDecoderT { |
+ public: |
+ virtual ~STMTD() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const; |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+ virtual Register base_address_register(Instruction i) const; |
+ virtual RegisterList immediate_addressing_defs(Instruction i) const; |
+}; |
+ |
+class LDMTD : public STMTD { |
+ public: |
+ virtual ~LDMTD() {} |
+ virtual RegisterList defs(Instruction i) const; |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return false; |
+ } |
+}; |
+ |
+class StrS : public STMTD { |
+ public: |
+ virtual ~StrS() {} |
+ virtual Register base_address_register(Instruction i) const; |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class LDRImmT3 : public ClassDecoderT { |
+ public: |
+ virtual ~LDRImmT3() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual RegisterList defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ virtual Register base_address_register(Instruction i) const; |
+}; |
+ |
+class LDRImmT4 : public LDRImmT3 { |
+ public: |
+ virtual ~LDRImmT4() {} |
+ virtual RegisterList immediate_addressing_defs(Instruction i) const; |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class Def31_18 : public Def3 { |
+ public: |
+ virtual ~Def31_18() {} |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class StrEx : public Def3 { |
+ public: |
+ virtual ~StrEx() {} |
+ virtual RegisterList defs(Instruction i) const; |
+ virtual RegisterList immediate_addressing_defs(Instruction i) const; |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return true; |
+ } |
+ virtual Register base_address_register(Instruction i) const; |
+}; |
+ |
+class LdrEx : public StrEx { |
+ public: |
+ virtual ~LdrEx() {} |
+ virtual RegisterList defs(Instruction i) const; |
+ virtual bool writes_memory(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return false; |
+ } |
+}; |
+ |
+class StrD : public StrEx { |
+ public: |
+ virtual ~StrD() {} |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class LdrD : public LdrEx { |
+ public: |
+ virtual ~LdrD() {} |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+class StrExD : public StrEx { |
+ public: |
+ virtual ~StrExD() {} |
+ virtual RegisterList immediate_addressing_defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; // Writeback not available |
+ } |
+}; |
+ |
+class LdrExD : public LdrD { |
+ public: |
+ virtual ~LdrExD() {} |
+ virtual RegisterList immediate_addressing_defs(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; // Writeback not available |
+ } |
+}; |
+ |
+class Def27_24 : public Def3 { |
+ public: |
+ virtual ~Def27_24() {} |
+ virtual RegisterList defs(Instruction i) const; |
+}; |
+ |
+/* Unimplemented Thumb instructions go here */ |
+#define THUMB_TODO(x) class x : public Forbidden {}; |
+THUMB_TODO(Unimplemented) |
} // namespace |
#endif // NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_V2_INST_CLASSES_H |