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