| Index: src/trusted/validator_arm/inst_classes.cc
|
| diff --git a/src/trusted/validator_arm/inst_classes.cc b/src/trusted/validator_arm/inst_classes.cc
|
| index 9b7a9bac7692a0445e363f82d5b42382b6cee436..7cff554884ff26bdd057dec416b3f581741477b9 100644
|
| --- a/src/trusted/validator_arm/inst_classes.cc
|
| +++ b/src/trusted/validator_arm/inst_classes.cc
|
| @@ -5,7 +5,8 @@
|
| */
|
|
|
| #include "native_client/src/trusted/validator_arm/inst_classes.h"
|
| -
|
| +// TODO(jasonwkim) remove when debug is gone
|
| +#include <stdio.h>
|
| /*
|
| * Implementations of instruction classes, for those not completely defined in
|
| * the header.
|
| @@ -419,4 +420,276 @@ int32_t Branch::branch_target_offset(const Instruction i) const {
|
| return offset + 8; // because r15 reads as 8 bytes ahead
|
| }
|
|
|
| +/* Thumb Functions */
|
| +SafetyLevel Def3::safety(Instruction i) const {
|
| + /* If it tries to write to PC, unsafe */
|
| + if (defs(i)[kRegisterPc]) {
|
| + return FORBIDDEN_OPERANDS;
|
| + }
|
| + return MAY_BE_SAFE;
|
| +}
|
| +
|
| +RegisterList Def3::defs(Instruction i) const {
|
| + return i.reg(3, 0);
|
| +}
|
| +
|
| +SafetyLevel Def8_10::safety(Instruction i) const {
|
| + // TODO(jasonwkim) should be encoding impossible, check
|
| + if (defs(i)[kRegisterPc]) {
|
| + return FORBIDDEN_OPERANDS;
|
| + }
|
| + return MAY_BE_SAFE;
|
| +}
|
| +
|
| +RegisterList Def8_10::defs(Instruction i) const {
|
| + return i.reg(10, 8);
|
| +}
|
| +
|
| +SafetyLevel MemOpThumb::safety(Instruction i) const {
|
| + // Don't let addressing writeback alter PC.
|
| + // TODO(jasonwkim): Check if this is possible, we may be able to remove this.
|
| + if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;
|
| +
|
| + return MAY_BE_SAFE;
|
| +}
|
| +
|
| +Register MemOpThumb::base_address_register(Instruction i) const {
|
| + return i.reg(5, 3);
|
| +}
|
| +
|
| +RegisterList MemOpThumbLoad::defs(Instruction i) const {
|
| + return i.reg(2, 0);
|
| +}
|
| +
|
| +// TODO(jasonwkim) double check, this is suspect
|
| +// Specifically, double check if I need to +4 things?
|
| +int32_t CmpBrZ::branch_target_offset(Instruction i) const {
|
| + return int32_t ((i.bits(9, 9) << 6) & (i.bits(7, 3) << 1));
|
| +}
|
| +
|
| +RegisterList PopMult::defs(Instruction i) const {
|
| + return RegisterList(i.bits(7, 0)) + kRegisterStack;
|
| +}
|
| +
|
| +SafetyLevel BranchTCond::safety(Instruction i) const {
|
| + if ((condition(i) & 14) != 14)
|
| + return MAY_BE_SAFE;
|
| + return FORBIDDEN_OPERANDS;
|
| +}
|
| +
|
| +// TODO(jasonwkim) Check if I need to +4
|
| +int32_t BranchT1::branch_target_offset(Instruction i) const {
|
| + // Sign extend and left shift by one
|
| + return ((int32_t)(i.bits(7, 0) << 24)) >> 23;
|
| +}
|
| +
|
| +// TODO(jasonwkim) write test
|
| +Instruction::Condition BranchT1::condition(Instruction i) const {
|
| + return (Instruction::Condition)i.bits(11, 8);
|
| +}
|
| +
|
| +// TODO(jasonwkim) Check if I need to +4
|
| +int32_t BranchT2::branch_target_offset(Instruction i) const {
|
| + // Sign extend and left shift by one.
|
| + return ((int32_t)(i.bits(10, 0) << 21)) >> 20;
|
| +}
|
| +
|
| +// TODO(jasonwkim) Check if I need to +4
|
| +int32_t BranchT3::branch_target_offset(Instruction i) const {
|
| + // Construct the value
|
| + uint32_t val = ((((((((i.bit(10) << 1) | i.bit(27)) << 1) | i.bit(29)) << 6)
|
| + | i.bits(5, 0)) << 11) | i.bits(26, 16)) << 1;
|
| + // Sign extend it.
|
| + return ((int32_t)(val << 9)) >> 9;
|
| +}
|
| +
|
| +Instruction::Condition BranchT3::condition(Instruction i) const {
|
| + return (Instruction::Condition)i.bits(9, 6);
|
| +}
|
| +
|
| +int32_t get_stretched_immediate(Instruction i) {
|
| + uint32_t s = i.bit(10);
|
| + uint32_t i1 = (~(i.bit(27) ^ s)) & 1;
|
| + uint32_t i2 = (~(i.bit(29) ^ s)) & 1;
|
| + // Construct the value
|
| + uint32_t val = ((((((((i.bit(10) << 1) | i1) << 1) | i2) << 10)
|
| + | i.bits(9, 0)) << 11) | i.bits(26, 16)) << 1;
|
| + // Sign extend it, adjust for pc shift
|
| + return (((int32_t)(val << 9)) >> 9);
|
| +}
|
| +
|
| +int32_t BranchT4::branch_target_offset(Instruction i) const {
|
| + return get_stretched_immediate(i) + 4;
|
| +}
|
| +
|
| +// TODO(jasonwkim) LDMT1/STMT1 could be cleaned up
|
| +RegisterList LDMT1::defs(Instruction i) const {
|
| + return RegisterList(i.bits(7, 0));
|
| +}
|
| +
|
| +RegisterList STMT1::defs(Instruction i) const {
|
| + return RegisterList(i.bits(7, 0)) + i.reg(10, 8);
|
| +}
|
| +
|
| +RegisterList STMT1::immediate_addressing_defs(Instruction i) const {
|
| + return i.reg(10, 8);
|
| +}
|
| +
|
| +Register STMT1::base_address_register(Instruction i) const {
|
| + return i.reg(10, 8);
|
| +}
|
| +
|
| +RegisterList LDRLitT1::defs(Instruction i) const {
|
| + return i.reg(10, 8);
|
| +}
|
| +
|
| +RegisterList ADRT1::defs(Instruction i) const {
|
| + return i.reg(10, 8);
|
| +}
|
| +
|
| +RegisterList MemOpSPThumbLoad::defs(Instruction i) const {
|
| + return i.reg(10, 8);
|
| +}
|
| +
|
| +RegisterList DPMImm::defs(Instruction i) const {
|
| + return i.reg(27, 24);
|
| +}
|
| +
|
| +uint32_t get_thumb_modified_immediate(Instruction i) {
|
| + uint32_t raw = i.bits(23, 16);
|
| + uint8_t shift_mode = (((i.bits(10, 10) << 3) | i.bits(30, 28)) << 1)
|
| + | i.bits(23, 23);
|
| + switch (shift_mode >> 1) {
|
| + case 0: return raw;
|
| + case 1: return (raw << 16) | raw;
|
| + case 2: return ((raw << 16) | raw) << 8;
|
| + case 3: return (((((raw << 8) | raw) << 8) | raw) << 8) | raw;
|
| + default: return (raw | (1 << 7)) << (31 - 7 - (shift_mode - 8));
|
| + };
|
| +}
|
| +
|
| +bool BicModImmT::clears_bits(Instruction i, uint32_t mask) const {
|
| + return (get_thumb_modified_immediate(i) & mask) == mask;
|
| +}
|
| +
|
| +bool OrrModImmT::sets_bits(Instruction i, uint32_t mask) const {
|
| + return get_thumb_modified_immediate(i) == mask;
|
| +}
|
| +
|
| +RegisterList MovT::defs(Instruction i) const {
|
| + return Register((i.bits(7, 7) << 3) | i.bits(2, 0));
|
| +}
|
| +
|
| +Register BXT::branch_target_register(Instruction i) const {
|
| + return i.reg(6, 3);
|
| +}
|
| +
|
| +int32_t BLT::branch_target_offset(Instruction i) const {
|
| + return get_stretched_immediate(i);
|
| +}
|
| +
|
| +ITCond IT::it_sequence(Instruction i) const {
|
| + uint32_t firstmask = i.bit(4);
|
| + ITCond base = it_set(0, THEN, 0);
|
| + uint32_t maskdex = 0;
|
| + while (i.bit(maskdex) == 0)
|
| + maskdex++;
|
| + // TODO(jasonwkim) Add a guard to the parse table to make sure
|
| + // the mask is never 0
|
| + maskdex++;
|
| + for (uint32_t conddex = 1; maskdex < 4; maskdex++, conddex++) {
|
| + base = it_set(conddex, i.bit(maskdex) == firstmask ? THEN : ELSE, base);
|
| + }
|
| + return base;
|
| +}
|
| +
|
| +Instruction::Condition IT::condition(Instruction i) const {
|
| + return (Instruction::Condition)i.bits(7, 4);
|
| +}
|
| +
|
| +RegisterList STMTD::defs(Instruction i) const {
|
| + return i.reg(3, 0);
|
| +}
|
| +
|
| +Register STMTD::base_address_register(Instruction i) const {
|
| + return i.reg(3, 0);
|
| +}
|
| +
|
| +RegisterList STMTD::immediate_addressing_defs(Instruction i) const {
|
| + return base_address_register(i);
|
| +}
|
| +
|
| +RegisterList LDMTD::defs(Instruction i) const {
|
| + return i.reg(3, 0) + RegisterList(i.bits(12, 0));
|
| +}
|
| +
|
| +Register StrS::base_address_register(Instruction i) const {
|
| + return i.reg(3, 0);
|
| +}
|
| +
|
| +// Note that while this doesn't always write something to i.reg(3, 0), it is
|
| +// safe to pretend that it does.
|
| +RegisterList StrS::defs(Instruction i) const {
|
| + return i.reg(3, 0);
|
| +}
|
| +
|
| +Register LDRImmT3::base_address_register(Instruction i) const {
|
| + return i.reg(3, 0);
|
| +}
|
| +
|
| +RegisterList LDRImmT4::defs(Instruction i) const {
|
| + if (i.bit(8 + 16)) {
|
| + return base_address_register(i); // Writeback
|
| + } else {
|
| + return kRegisterNone;
|
| + }
|
| +}
|
| +
|
| +RegisterList LDRImmT4::immediate_addressing_defs(Instruction i) const {
|
| + return defs(i);
|
| +}
|
| +
|
| +RegisterList Def31_18::defs(Instruction i) const {
|
| + return i.reg(31, 18);
|
| +}
|
| +
|
| +RegisterList StrEx::defs(Instruction i) const {
|
| + return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16);
|
| +}
|
| +
|
| +RegisterList StrEx::immediate_addressing_defs(Instruction i) const {
|
| + if (i.bit(5))
|
| + return base_address_register(i);
|
| + return kRegisterNone;
|
| +}
|
| +
|
| +Register StrEx::base_address_register(Instruction i) const {
|
| + return i.reg(3, 0);
|
| +}
|
| +
|
| +RegisterList LdrEx::defs(Instruction i) const {
|
| + return immediate_addressing_defs(i) + i.reg(15 + 16, 12 + 16);
|
| +}
|
| +
|
| +RegisterList StrD::defs(Instruction i) const {
|
| + return immediate_addressing_defs(i);
|
| +}
|
| +
|
| +RegisterList LdrD::defs(Instruction i) const {
|
| + return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16)
|
| + + i.reg(15 + 16, 12 + 16);
|
| +}
|
| +
|
| +RegisterList Def27_24::defs(Instruction i) const {
|
| + return i.reg(27, 24);
|
| +}
|
| +
|
| +bool ThumbBreakpoint::is_literal_pool_head(Instruction i) const {
|
| + UNREFERENCED_PARAMETER(i);
|
| + // TODO(jasonwkim) We ideally want to think about conditions, but due to the
|
| + // rule that IT cannot straddle a boundary, and this has to start
|
| + // a bundle, we're fine.
|
| + return true;
|
| +}
|
| +
|
| } // namespace
|
|
|