decoder.cc revision 9376:270c9a75e91f
13005Sstever@eecs.umich.edu/*
23005Sstever@eecs.umich.edu * Copyright (c) 2011 Google
33005Sstever@eecs.umich.edu * All rights reserved.
43005Sstever@eecs.umich.edu *
53005Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
63005Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
73005Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
83005Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
93005Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
103005Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
113005Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
123005Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
133005Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
143005Sstever@eecs.umich.edu * this software without specific prior written permission.
153005Sstever@eecs.umich.edu *
163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu *
283005Sstever@eecs.umich.edu * Authors: Gabe Black
292889SN/A */
302889SN/A
312710SN/A#include "arch/x86/decoder.hh"
322710SN/A#include "arch/x86/regs/misc.hh"
332934SN/A#include "base/misc.hh"
342934SN/A#include "base/trace.hh"
352549SN/A#include "base/types.hh"
362995SN/A#include "cpu/thread_context.hh"
373395Shsul@eecs.umich.edu#include "debug/Decoder.hh"
383448Shsul@eecs.umich.edu
392549SN/Anamespace X86ISA
403088Sstever@eecs.umich.edu{
413088Sstever@eecs.umich.edu
423088Sstever@eecs.umich.eduDecoder::State
433444Sktlim@umich.eduDecoder::doResetState()
443444Sktlim@umich.edu{
453444Sktlim@umich.edu    origPC = basePC + offset;
463444Sktlim@umich.edu    DPRINTF(Decoder, "Setting origPC to %#x\n", origPC);
472889SN/A    instBytes = &decodePages->lookup(origPC);
482710SN/A    chunkIdx = 0;
493322Shsul@eecs.umich.edu
503668Srdreslin@umich.edu    emi.rex = 0;
512995SN/A    emi.legacy = 0;
522995SN/A    emi.opcode.num = 0;
532995SN/A    emi.opcode.op = 0;
542995SN/A    emi.opcode.prefixA = emi.opcode.prefixB = 0;
552995SN/A
563143Shsul@eecs.umich.edu    immediateCollected = 0;
573322Shsul@eecs.umich.edu    emi.immediate = 0;
583322Shsul@eecs.umich.edu    emi.displacement = 0;
593025Ssaidi@eecs.umich.edu    emi.dispSize = 0;
603143Shsul@eecs.umich.edu
613143Shsul@eecs.umich.edu    emi.modRM = 0;
623322Shsul@eecs.umich.edu    emi.sib = 0;
633444Sktlim@umich.edu
643322Shsul@eecs.umich.edu    if (instBytes->si) {
652710SN/A        return FromCacheState;
662710SN/A    } else {
672710SN/A        instBytes->chunks.clear();
682710SN/A        return PrefixState;
692710SN/A    }
702710SN/A}
713322Shsul@eecs.umich.edu
723304Sstever@eecs.umich.eduvoid
733322Shsul@eecs.umich.eduDecoder::process()
743322Shsul@eecs.umich.edu{
753304Sstever@eecs.umich.edu    //This function drives the decoder state machine.
763481Shsul@eecs.umich.edu
773481Shsul@eecs.umich.edu    //Some sanity checks. You shouldn't try to process more bytes if
782566SN/A    //there aren't any, and you shouldn't overwrite an already
793322Shsul@eecs.umich.edu    //decoder ExtMachInst.
803322Shsul@eecs.umich.edu    assert(!outOfBytes);
812995SN/A    assert(!instDone);
822995SN/A
833304Sstever@eecs.umich.edu    if (state == ResetState)
843304Sstever@eecs.umich.edu        state = doResetState();
853304Sstever@eecs.umich.edu    if (state == FromCacheState) {
862995SN/A        state = doFromCacheState();
872995SN/A    } else {
882995SN/A        instBytes->chunks.push_back(fetchChunk);
892917SN/A    }
902995SN/A
913304Sstever@eecs.umich.edu    //While there's still something to do...
922995SN/A    while (!instDone && !outOfBytes) {
933304Sstever@eecs.umich.edu        uint8_t nextByte = getNextByte();
943304Sstever@eecs.umich.edu        switch (state) {
953819Shsul@eecs.umich.edu          case PrefixState:
963819Shsul@eecs.umich.edu            state = doPrefixState(nextByte);
973819Shsul@eecs.umich.edu            break;
983819Shsul@eecs.umich.edu          case OpcodeState:
993819Shsul@eecs.umich.edu            state = doOpcodeState(nextByte);
1003819Shsul@eecs.umich.edu            break;
1013819Shsul@eecs.umich.edu          case ModRMState:
1023312Sstever@eecs.umich.edu            state = doModRMState(nextByte);
1033668Srdreslin@umich.edu            break;
1043668Srdreslin@umich.edu          case SIBState:
1053668Srdreslin@umich.edu            state = doSIBState(nextByte);
1063668Srdreslin@umich.edu            break;
1073668Srdreslin@umich.edu          case DisplacementState:
1083668Srdreslin@umich.edu            state = doDisplacementState();
1093668Srdreslin@umich.edu            break;
1103322Shsul@eecs.umich.edu          case ImmediateState:
1113312Sstever@eecs.umich.edu            state = doImmediateState();
1123514Sktlim@umich.edu            break;
1133395Shsul@eecs.umich.edu          case ErrorState:
1143448Shsul@eecs.umich.edu            panic("Went to the error state in the decoder.\n");
1153668Srdreslin@umich.edu          default:
1163668Srdreslin@umich.edu            panic("Unrecognized state! %d\n", state);
1173668Srdreslin@umich.edu        }
1183668Srdreslin@umich.edu    }
1193668Srdreslin@umich.edu}
1203005Sstever@eecs.umich.edu
1213005Sstever@eecs.umich.eduDecoder::State
1223819Shsul@eecs.umich.eduDecoder::doFromCacheState()
1233819Shsul@eecs.umich.edu{
1243819Shsul@eecs.umich.edu    DPRINTF(Decoder, "Looking at cache state.\n");
1253819Shsul@eecs.umich.edu    if ((fetchChunk & instBytes->masks[chunkIdx]) !=
1263322Shsul@eecs.umich.edu            instBytes->chunks[chunkIdx]) {
1273322Shsul@eecs.umich.edu        DPRINTF(Decoder, "Decode cache miss.\n");
1283322Shsul@eecs.umich.edu        // The chached chunks didn't match what was fetched. Fall back to the
1293005Sstever@eecs.umich.edu        // predecoder.
1303322Shsul@eecs.umich.edu        instBytes->chunks[chunkIdx] = fetchChunk;
1313005Sstever@eecs.umich.edu        instBytes->chunks.resize(chunkIdx + 1);
1323005Sstever@eecs.umich.edu        instBytes->si = NULL;
1333005Sstever@eecs.umich.edu        chunkIdx = 0;
1342566SN/A        fetchChunk = instBytes->chunks[0];
1353481Shsul@eecs.umich.edu        offset = origPC % sizeof(MachInst);
136        basePC = origPC - offset;
137        return PrefixState;
138    } else if (chunkIdx == instBytes->chunks.size() - 1) {
139        // We matched the cache, so use its value.
140        instDone = true;
141        offset = instBytes->lastOffset;
142        if (offset == sizeof(MachInst))
143            outOfBytes = true;
144        return ResetState;
145    } else {
146        // We matched so far, but need to check more chunks.
147        chunkIdx++;
148        outOfBytes = true;
149        return FromCacheState;
150    }
151}
152
153//Either get a prefix and record it in the ExtMachInst, or send the
154//state machine on to get the opcode(s).
155Decoder::State
156Decoder::doPrefixState(uint8_t nextByte)
157{
158    uint8_t prefix = Prefixes[nextByte];
159    State nextState = PrefixState;
160    // REX prefixes are only recognized in 64 bit mode.
161    if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
162        prefix = 0;
163    if (prefix)
164        consumeByte();
165    switch(prefix)
166    {
167        //Operand size override prefixes
168      case OperandSizeOverride:
169        DPRINTF(Decoder, "Found operand size override prefix.\n");
170        emi.legacy.op = true;
171        break;
172      case AddressSizeOverride:
173        DPRINTF(Decoder, "Found address size override prefix.\n");
174        emi.legacy.addr = true;
175        break;
176        //Segment override prefixes
177      case CSOverride:
178      case DSOverride:
179      case ESOverride:
180      case FSOverride:
181      case GSOverride:
182      case SSOverride:
183        DPRINTF(Decoder, "Found segment override.\n");
184        emi.legacy.seg = prefix;
185        break;
186      case Lock:
187        DPRINTF(Decoder, "Found lock prefix.\n");
188        emi.legacy.lock = true;
189        break;
190      case Rep:
191        DPRINTF(Decoder, "Found rep prefix.\n");
192        emi.legacy.rep = true;
193        break;
194      case Repne:
195        DPRINTF(Decoder, "Found repne prefix.\n");
196        emi.legacy.repne = true;
197        break;
198      case RexPrefix:
199        DPRINTF(Decoder, "Found Rex prefix %#x.\n", nextByte);
200        emi.rex = nextByte;
201        break;
202      case 0:
203        nextState = OpcodeState;
204        break;
205      default:
206        panic("Unrecognized prefix %#x\n", nextByte);
207    }
208    return nextState;
209}
210
211//Load all the opcodes (currently up to 2) and then figure out
212//what immediate and/or ModRM is needed.
213Decoder::State
214Decoder::doOpcodeState(uint8_t nextByte)
215{
216    State nextState = ErrorState;
217    emi.opcode.num++;
218    //We can't handle 3+ byte opcodes right now
219    assert(emi.opcode.num < 4);
220    consumeByte();
221    if(emi.opcode.num == 1 && nextByte == 0x0f)
222    {
223        nextState = OpcodeState;
224        DPRINTF(Decoder, "Found two byte opcode.\n");
225        emi.opcode.prefixA = nextByte;
226    }
227    else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A))
228    {
229        nextState = OpcodeState;
230        DPRINTF(Decoder, "Found three byte opcode.\n");
231        emi.opcode.prefixB = nextByte;
232    }
233    else
234    {
235        DPRINTF(Decoder, "Found opcode %#x.\n", nextByte);
236        emi.opcode.op = nextByte;
237
238        //Figure out the effective operand size. This can be overriden to
239        //a fixed value at the decoder level.
240        int logOpSize;
241        if (emi.rex.w)
242            logOpSize = 3; // 64 bit operand size
243        else if (emi.legacy.op)
244            logOpSize = altOp;
245        else
246            logOpSize = defOp;
247
248        //Set the actual op size
249        emi.opSize = 1 << logOpSize;
250
251        //Figure out the effective address size. This can be overriden to
252        //a fixed value at the decoder level.
253        int logAddrSize;
254        if(emi.legacy.addr)
255            logAddrSize = altAddr;
256        else
257            logAddrSize = defAddr;
258
259        //Set the actual address size
260        emi.addrSize = 1 << logAddrSize;
261
262        //Figure out the effective stack width. This can be overriden to
263        //a fixed value at the decoder level.
264        emi.stackSize = 1 << stack;
265
266        //Figure out how big of an immediate we'll retreive based
267        //on the opcode.
268        int immType = ImmediateType[emi.opcode.num - 1][nextByte];
269        if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
270            immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
271        else
272            immediateSize = SizeTypeToSize[logOpSize - 1][immType];
273
274        //Determine what to expect next
275        if (UsesModRM[emi.opcode.num - 1][nextByte]) {
276            nextState = ModRMState;
277        } else {
278            if(immediateSize) {
279                nextState = ImmediateState;
280            } else {
281                instDone = true;
282                nextState = ResetState;
283            }
284        }
285    }
286    return nextState;
287}
288
289//Get the ModRM byte and determine what displacement, if any, there is.
290//Also determine whether or not to get the SIB byte, displacement, or
291//immediate next.
292Decoder::State
293Decoder::doModRMState(uint8_t nextByte)
294{
295    State nextState = ErrorState;
296    ModRM modRM;
297    modRM = nextByte;
298    DPRINTF(Decoder, "Found modrm byte %#x.\n", nextByte);
299    if (defOp == 1) {
300        //figure out 16 bit displacement size
301        if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
302            displacementSize = 2;
303        else if (modRM.mod == 1)
304            displacementSize = 1;
305        else
306            displacementSize = 0;
307    } else {
308        //figure out 32/64 bit displacement size
309        if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
310            displacementSize = 4;
311        else if (modRM.mod == 1)
312            displacementSize = 1;
313        else
314            displacementSize = 0;
315    }
316
317    // The "test" instruction in group 3 needs an immediate, even though
318    // the other instructions with the same actual opcode don't.
319    if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
320       if (emi.opcode.op == 0xF6)
321           immediateSize = 1;
322       else if (emi.opcode.op == 0xF7)
323           immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
324    }
325
326    //If there's an SIB, get that next.
327    //There is no SIB in 16 bit mode.
328    if (modRM.rm == 4 && modRM.mod != 3) {
329            // && in 32/64 bit mode)
330        nextState = SIBState;
331    } else if(displacementSize) {
332        nextState = DisplacementState;
333    } else if(immediateSize) {
334        nextState = ImmediateState;
335    } else {
336        instDone = true;
337        nextState = ResetState;
338    }
339    //The ModRM byte is consumed no matter what
340    consumeByte();
341    emi.modRM = modRM;
342    return nextState;
343}
344
345//Get the SIB byte. We don't do anything with it at this point, other
346//than storing it in the ExtMachInst. Determine if we need to get a
347//displacement or immediate next.
348Decoder::State
349Decoder::doSIBState(uint8_t nextByte)
350{
351    State nextState = ErrorState;
352    emi.sib = nextByte;
353    DPRINTF(Decoder, "Found SIB byte %#x.\n", nextByte);
354    consumeByte();
355    if (emi.modRM.mod == 0 && emi.sib.base == 5)
356        displacementSize = 4;
357    if (displacementSize) {
358        nextState = DisplacementState;
359    } else if(immediateSize) {
360        nextState = ImmediateState;
361    } else {
362        instDone = true;
363        nextState = ResetState;
364    }
365    return nextState;
366}
367
368//Gather up the displacement, or at least as much of it
369//as we can get.
370Decoder::State
371Decoder::doDisplacementState()
372{
373    State nextState = ErrorState;
374
375    getImmediate(immediateCollected,
376            emi.displacement,
377            displacementSize);
378
379    DPRINTF(Decoder, "Collecting %d byte displacement, got %d bytes.\n",
380            displacementSize, immediateCollected);
381
382    if(displacementSize == immediateCollected) {
383        //Reset this for other immediates.
384        immediateCollected = 0;
385        //Sign extend the displacement
386        switch(displacementSize)
387        {
388          case 1:
389            emi.displacement = sext<8>(emi.displacement);
390            break;
391          case 2:
392            emi.displacement = sext<16>(emi.displacement);
393            break;
394          case 4:
395            emi.displacement = sext<32>(emi.displacement);
396            break;
397          default:
398            panic("Undefined displacement size!\n");
399        }
400        DPRINTF(Decoder, "Collected displacement %#x.\n",
401                emi.displacement);
402        if(immediateSize) {
403            nextState = ImmediateState;
404        } else {
405            instDone = true;
406            nextState = ResetState;
407        }
408
409        emi.dispSize = displacementSize;
410    }
411    else
412        nextState = DisplacementState;
413    return nextState;
414}
415
416//Gather up the immediate, or at least as much of it
417//as we can get
418Decoder::State
419Decoder::doImmediateState()
420{
421    State nextState = ErrorState;
422
423    getImmediate(immediateCollected,
424            emi.immediate,
425            immediateSize);
426
427    DPRINTF(Decoder, "Collecting %d byte immediate, got %d bytes.\n",
428            immediateSize, immediateCollected);
429
430    if(immediateSize == immediateCollected)
431    {
432        //Reset this for other immediates.
433        immediateCollected = 0;
434
435        //XXX Warning! The following is an observed pattern and might
436        //not always be true!
437
438        //Instructions which use 64 bit operands but 32 bit immediates
439        //need to have the immediate sign extended to 64 bits.
440        //Instructions which use true 64 bit immediates won't be
441        //affected, and instructions that use true 32 bit immediates
442        //won't notice.
443        switch(immediateSize)
444        {
445          case 4:
446            emi.immediate = sext<32>(emi.immediate);
447            break;
448          case 1:
449            emi.immediate = sext<8>(emi.immediate);
450        }
451
452        DPRINTF(Decoder, "Collected immediate %#x.\n",
453                emi.immediate);
454        instDone = true;
455        nextState = ResetState;
456    }
457    else
458        nextState = ImmediateState;
459    return nextState;
460}
461
462Decoder::InstBytes Decoder::dummy;
463Decoder::InstCacheMap Decoder::instCacheMap;
464
465StaticInstPtr
466Decoder::decode(ExtMachInst mach_inst, Addr addr)
467{
468    DecodeCache::InstMap::iterator iter = instMap->find(mach_inst);
469    if (iter != instMap->end())
470        return iter->second;
471
472    StaticInstPtr si = decodeInst(mach_inst);
473    (*instMap)[mach_inst] = si;
474    return si;
475}
476
477StaticInstPtr
478Decoder::decode(PCState &nextPC)
479{
480    if (!instDone)
481        return NULL;
482    instDone = false;
483    updateNPC(nextPC);
484
485    StaticInstPtr &si = instBytes->si;
486    if (si)
487        return si;
488
489    // We didn't match in the AddrMap, but we still populated an entry. Fix
490    // up its byte masks.
491    const int chunkSize = sizeof(MachInst);
492
493    instBytes->lastOffset = offset;
494
495    Addr firstBasePC = basePC - (instBytes->chunks.size() - 1) * chunkSize;
496    Addr firstOffset = origPC - firstBasePC;
497    Addr totalSize = instBytes->lastOffset - firstOffset +
498        (instBytes->chunks.size() - 1) * chunkSize;
499    int start = firstOffset;
500    instBytes->masks.clear();
501
502    while (totalSize) {
503        int end = start + totalSize;
504        end = (chunkSize < end) ? chunkSize : end;
505        int size = end - start;
506        int idx = instBytes->masks.size();
507
508        MachInst maskVal = mask(size * 8) << (start * 8);
509        assert(maskVal);
510
511        instBytes->masks.push_back(maskVal);
512        instBytes->chunks[idx] &= instBytes->masks[idx];
513        totalSize -= size;
514        start = 0;
515    }
516
517    si = decode(emi, origPC);
518    return si;
519}
520
521}
522