diff options
Diffstat (limited to 'src/arch/x86/decoder.cc')
-rw-r--r-- | src/arch/x86/decoder.cc | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/src/arch/x86/decoder.cc b/src/arch/x86/decoder.cc index 469858301..d7199fa82 100644 --- a/src/arch/x86/decoder.cc +++ b/src/arch/x86/decoder.cc @@ -29,9 +29,384 @@ */ #include "arch/x86/decoder.hh" +#include "arch/x86/regs/misc.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/types.hh" +#include "cpu/thread_context.hh" +#include "debug/Decoder.hh" namespace X86ISA { +void Decoder::doReset() +{ + origPC = basePC + offset; + DPRINTF(Decoder, "Setting origPC to %#x\n", origPC); + emi.rex = 0; + emi.legacy = 0; + emi.opcode.num = 0; + emi.opcode.op = 0; + emi.opcode.prefixA = emi.opcode.prefixB = 0; + + immediateCollected = 0; + emi.immediate = 0; + emi.displacement = 0; + emi.dispSize = 0; + + emi.modRM = 0; + emi.sib = 0; + m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + emi.mode.mode = m5Reg.mode; + emi.mode.submode = m5Reg.submode; +} + +void Decoder::process() +{ + //This function drives the decoder state machine. + + //Some sanity checks. You shouldn't try to process more bytes if + //there aren't any, and you shouldn't overwrite an already + //decoder ExtMachInst. + assert(!outOfBytes); + assert(!instDone); + + //While there's still something to do... + while(!instDone && !outOfBytes) + { + uint8_t nextByte = getNextByte(); + switch(state) + { + case ResetState: + doReset(); + state = PrefixState; + case PrefixState: + state = doPrefixState(nextByte); + break; + case OpcodeState: + state = doOpcodeState(nextByte); + break; + case ModRMState: + state = doModRMState(nextByte); + break; + case SIBState: + state = doSIBState(nextByte); + break; + case DisplacementState: + state = doDisplacementState(); + break; + case ImmediateState: + state = doImmediateState(); + break; + case ErrorState: + panic("Went to the error state in the decoder.\n"); + default: + panic("Unrecognized state! %d\n", state); + } + } +} + +//Either get a prefix and record it in the ExtMachInst, or send the +//state machine on to get the opcode(s). +Decoder::State Decoder::doPrefixState(uint8_t nextByte) +{ + uint8_t prefix = Prefixes[nextByte]; + State nextState = PrefixState; + // REX prefixes are only recognized in 64 bit mode. + if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode) + prefix = 0; + if (prefix) + consumeByte(); + switch(prefix) + { + //Operand size override prefixes + case OperandSizeOverride: + DPRINTF(Decoder, "Found operand size override prefix.\n"); + emi.legacy.op = true; + break; + case AddressSizeOverride: + DPRINTF(Decoder, "Found address size override prefix.\n"); + emi.legacy.addr = true; + break; + //Segment override prefixes + case CSOverride: + case DSOverride: + case ESOverride: + case FSOverride: + case GSOverride: + case SSOverride: + DPRINTF(Decoder, "Found segment override.\n"); + emi.legacy.seg = prefix; + break; + case Lock: + DPRINTF(Decoder, "Found lock prefix.\n"); + emi.legacy.lock = true; + break; + case Rep: + DPRINTF(Decoder, "Found rep prefix.\n"); + emi.legacy.rep = true; + break; + case Repne: + DPRINTF(Decoder, "Found repne prefix.\n"); + emi.legacy.repne = true; + break; + case RexPrefix: + DPRINTF(Decoder, "Found Rex prefix %#x.\n", nextByte); + emi.rex = nextByte; + break; + case 0: + nextState = OpcodeState; + break; + default: + panic("Unrecognized prefix %#x\n", nextByte); + } + return nextState; +} + +//Load all the opcodes (currently up to 2) and then figure out +//what immediate and/or ModRM is needed. +Decoder::State Decoder::doOpcodeState(uint8_t nextByte) +{ + State nextState = ErrorState; + emi.opcode.num++; + //We can't handle 3+ byte opcodes right now + assert(emi.opcode.num < 4); + consumeByte(); + if(emi.opcode.num == 1 && nextByte == 0x0f) + { + nextState = OpcodeState; + DPRINTF(Decoder, "Found two byte opcode.\n"); + emi.opcode.prefixA = nextByte; + } + else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A)) + { + nextState = OpcodeState; + DPRINTF(Decoder, "Found three byte opcode.\n"); + emi.opcode.prefixB = nextByte; + } + else + { + DPRINTF(Decoder, "Found opcode %#x.\n", nextByte); + emi.opcode.op = nextByte; + + //Figure out the effective operand size. This can be overriden to + //a fixed value at the decoder level. + int logOpSize; + if (emi.rex.w) + logOpSize = 3; // 64 bit operand size + else if (emi.legacy.op) + logOpSize = m5Reg.altOp; + else + logOpSize = m5Reg.defOp; + + //Set the actual op size + emi.opSize = 1 << logOpSize; + + //Figure out the effective address size. This can be overriden to + //a fixed value at the decoder level. + int logAddrSize; + if(emi.legacy.addr) + logAddrSize = m5Reg.altAddr; + else + logAddrSize = m5Reg.defAddr; + + //Set the actual address size + emi.addrSize = 1 << logAddrSize; + + //Figure out the effective stack width. This can be overriden to + //a fixed value at the decoder level. + emi.stackSize = 1 << m5Reg.stack; + + //Figure out how big of an immediate we'll retreive based + //on the opcode. + int immType = ImmediateType[emi.opcode.num - 1][nextByte]; + if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3) + immediateSize = SizeTypeToSize[logAddrSize - 1][immType]; + else + immediateSize = SizeTypeToSize[logOpSize - 1][immType]; + + //Determine what to expect next + if (UsesModRM[emi.opcode.num - 1][nextByte]) { + nextState = ModRMState; + } else { + if(immediateSize) { + nextState = ImmediateState; + } else { + instDone = true; + nextState = ResetState; + } + } + } + return nextState; +} + +//Get the ModRM byte and determine what displacement, if any, there is. +//Also determine whether or not to get the SIB byte, displacement, or +//immediate next. +Decoder::State Decoder::doModRMState(uint8_t nextByte) +{ + State nextState = ErrorState; + ModRM modRM; + modRM = nextByte; + DPRINTF(Decoder, "Found modrm byte %#x.\n", nextByte); + if (m5Reg.defOp == 1) { + //figure out 16 bit displacement size + if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2) + displacementSize = 2; + else if (modRM.mod == 1) + displacementSize = 1; + else + displacementSize = 0; + } else { + //figure out 32/64 bit displacement size + if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2) + displacementSize = 4; + else if (modRM.mod == 1) + displacementSize = 1; + else + displacementSize = 0; + } + + // The "test" instruction in group 3 needs an immediate, even though + // the other instructions with the same actual opcode don't. + if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) { + if (emi.opcode.op == 0xF6) + immediateSize = 1; + else if (emi.opcode.op == 0xF7) + immediateSize = (emi.opSize == 8) ? 4 : emi.opSize; + } + + //If there's an SIB, get that next. + //There is no SIB in 16 bit mode. + if (modRM.rm == 4 && modRM.mod != 3) { + // && in 32/64 bit mode) + nextState = SIBState; + } else if(displacementSize) { + nextState = DisplacementState; + } else if(immediateSize) { + nextState = ImmediateState; + } else { + instDone = true; + nextState = ResetState; + } + //The ModRM byte is consumed no matter what + consumeByte(); + emi.modRM = modRM; + return nextState; +} + +//Get the SIB byte. We don't do anything with it at this point, other +//than storing it in the ExtMachInst. Determine if we need to get a +//displacement or immediate next. +Decoder::State Decoder::doSIBState(uint8_t nextByte) +{ + State nextState = ErrorState; + emi.sib = nextByte; + DPRINTF(Decoder, "Found SIB byte %#x.\n", nextByte); + consumeByte(); + if (emi.modRM.mod == 0 && emi.sib.base == 5) + displacementSize = 4; + if (displacementSize) { + nextState = DisplacementState; + } else if(immediateSize) { + nextState = ImmediateState; + } else { + instDone = true; + nextState = ResetState; + } + return nextState; +} + +//Gather up the displacement, or at least as much of it +//as we can get. +Decoder::State Decoder::doDisplacementState() +{ + State nextState = ErrorState; + + getImmediate(immediateCollected, + emi.displacement, + displacementSize); + + DPRINTF(Decoder, "Collecting %d byte displacement, got %d bytes.\n", + displacementSize, immediateCollected); + + if(displacementSize == immediateCollected) { + //Reset this for other immediates. + immediateCollected = 0; + //Sign extend the displacement + switch(displacementSize) + { + case 1: + emi.displacement = sext<8>(emi.displacement); + break; + case 2: + emi.displacement = sext<16>(emi.displacement); + break; + case 4: + emi.displacement = sext<32>(emi.displacement); + break; + default: + panic("Undefined displacement size!\n"); + } + DPRINTF(Decoder, "Collected displacement %#x.\n", + emi.displacement); + if(immediateSize) { + nextState = ImmediateState; + } else { + instDone = true; + nextState = ResetState; + } + + emi.dispSize = displacementSize; + } + else + nextState = DisplacementState; + return nextState; +} + +//Gather up the immediate, or at least as much of it +//as we can get +Decoder::State Decoder::doImmediateState() +{ + State nextState = ErrorState; + + getImmediate(immediateCollected, + emi.immediate, + immediateSize); + + DPRINTF(Decoder, "Collecting %d byte immediate, got %d bytes.\n", + immediateSize, immediateCollected); + + if(immediateSize == immediateCollected) + { + //Reset this for other immediates. + immediateCollected = 0; + + //XXX Warning! The following is an observed pattern and might + //not always be true! + + //Instructions which use 64 bit operands but 32 bit immediates + //need to have the immediate sign extended to 64 bits. + //Instructions which use true 64 bit immediates won't be + //affected, and instructions that use true 32 bit immediates + //won't notice. + switch(immediateSize) + { + case 4: + emi.immediate = sext<32>(emi.immediate); + break; + case 1: + emi.immediate = sext<8>(emi.immediate); + } + + DPRINTF(Decoder, "Collected immediate %#x.\n", + emi.immediate); + instDone = true; + nextState = ResetState; + } + else + nextState = ImmediateState; + return nextState; +} DecodeCache Decoder::defaultCache; |