static_inst.cc revision 11513:cb3a401c45d7
1/*
2 * Copyright (c) 2010-2014, 2016 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder.  You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2007-2008 The Florida State University
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Stephen Hines
42 */
43
44#include "arch/arm/insts/static_inst.hh"
45#include "arch/arm/faults.hh"
46#include "base/loader/symtab.hh"
47#include "base/condcodes.hh"
48#include "base/cprintf.hh"
49#include "cpu/reg_class.hh"
50
51namespace ArmISA
52{
53// Shift Rm by an immediate value
54int32_t
55ArmStaticInst::shift_rm_imm(uint32_t base, uint32_t shamt,
56                                uint32_t type, uint32_t cfval) const
57{
58    assert(shamt < 32);
59    ArmShiftType shiftType;
60    shiftType = (ArmShiftType)type;
61
62    switch (shiftType)
63    {
64      case LSL:
65        return base << shamt;
66      case LSR:
67        if (shamt == 0)
68            return 0;
69        else
70            return base >> shamt;
71      case ASR:
72        if (shamt == 0)
73            return (base >> 31) | -((base & (1 << 31)) >> 31);
74        else
75            return (base >> shamt) | -((base & (1 << 31)) >> shamt);
76      case ROR:
77        if (shamt == 0)
78            return (cfval << 31) | (base >> 1); // RRX
79        else
80            return (base << (32 - shamt)) | (base >> shamt);
81      default:
82        ccprintf(std::cerr, "Unhandled shift type\n");
83        exit(1);
84        break;
85    }
86    return 0;
87}
88
89int64_t
90ArmStaticInst::shiftReg64(uint64_t base, uint64_t shiftAmt,
91                          ArmShiftType type, uint8_t width) const
92{
93    shiftAmt = shiftAmt % width;
94    ArmShiftType shiftType;
95    shiftType = (ArmShiftType)type;
96
97    switch (shiftType)
98    {
99      case LSL:
100        return base << shiftAmt;
101      case LSR:
102        if (shiftAmt == 0)
103            return base;
104        else
105            return (base & mask(width)) >> shiftAmt;
106      case ASR:
107        if (shiftAmt == 0) {
108            return base;
109        } else {
110            int sign_bit = bits(base, intWidth - 1);
111            base >>= shiftAmt;
112            base = sign_bit ? (base | ~mask(intWidth - shiftAmt)) : base;
113            return base & mask(intWidth);
114        }
115      case ROR:
116        if (shiftAmt == 0)
117            return base;
118        else
119            return (base << (width - shiftAmt)) | (base >> shiftAmt);
120      default:
121        ccprintf(std::cerr, "Unhandled shift type\n");
122        exit(1);
123        break;
124    }
125    return 0;
126}
127
128int64_t
129ArmStaticInst::extendReg64(uint64_t base, ArmExtendType type,
130                           uint64_t shiftAmt, uint8_t width) const
131{
132    bool sign_extend = false;
133    int len = 0;
134    switch (type) {
135      case UXTB:
136        len = 8;
137        break;
138      case UXTH:
139        len = 16;
140        break;
141      case UXTW:
142        len = 32;
143        break;
144      case UXTX:
145        len = 64;
146        break;
147      case SXTB:
148        len = 8;
149        sign_extend = true;
150        break;
151      case SXTH:
152        len = 16;
153        sign_extend = true;
154        break;
155      case SXTW:
156        len = 32;
157        sign_extend = true;
158        break;
159      case SXTX:
160        len = 64;
161        sign_extend = true;
162        break;
163    }
164    len = len <= width - shiftAmt ? len : width - shiftAmt;
165    uint64_t tmp = (uint64_t) bits(base, len - 1, 0) << shiftAmt;
166    if (sign_extend) {
167        int sign_bit = bits(tmp, len + shiftAmt - 1);
168        tmp = sign_bit ? (tmp | ~mask(len + shiftAmt)) : tmp;
169    }
170    return tmp & mask(width);
171}
172
173// Shift Rm by Rs
174int32_t
175ArmStaticInst::shift_rm_rs(uint32_t base, uint32_t shamt,
176                               uint32_t type, uint32_t cfval) const
177{
178    enum ArmShiftType shiftType;
179    shiftType = (enum ArmShiftType) type;
180
181    switch (shiftType)
182    {
183      case LSL:
184        if (shamt >= 32)
185            return 0;
186        else
187            return base << shamt;
188      case LSR:
189        if (shamt >= 32)
190            return 0;
191        else
192            return base >> shamt;
193      case ASR:
194        if (shamt >= 32)
195            return (base >> 31) | -((base & (1 << 31)) >> 31);
196        else
197            return (base >> shamt) | -((base & (1 << 31)) >> shamt);
198      case ROR:
199        shamt = shamt & 0x1f;
200        if (shamt == 0)
201            return base;
202        else
203            return (base << (32 - shamt)) | (base >> shamt);
204      default:
205        ccprintf(std::cerr, "Unhandled shift type\n");
206        exit(1);
207        break;
208    }
209    return 0;
210}
211
212
213// Generate C for a shift by immediate
214bool
215ArmStaticInst::shift_carry_imm(uint32_t base, uint32_t shamt,
216                                   uint32_t type, uint32_t cfval) const
217{
218    enum ArmShiftType shiftType;
219    shiftType = (enum ArmShiftType) type;
220
221    switch (shiftType)
222    {
223      case LSL:
224        if (shamt == 0)
225            return cfval;
226        else
227            return (base >> (32 - shamt)) & 1;
228      case LSR:
229        if (shamt == 0)
230            return (base >> 31);
231        else
232            return (base >> (shamt - 1)) & 1;
233      case ASR:
234        if (shamt == 0)
235            return (base >> 31);
236        else
237            return (base >> (shamt - 1)) & 1;
238      case ROR:
239        shamt = shamt & 0x1f;
240        if (shamt == 0)
241            return (base & 1); // RRX
242        else
243            return (base >> (shamt - 1)) & 1;
244      default:
245        ccprintf(std::cerr, "Unhandled shift type\n");
246        exit(1);
247        break;
248    }
249    return 0;
250}
251
252
253// Generate C for a shift by Rs
254bool
255ArmStaticInst::shift_carry_rs(uint32_t base, uint32_t shamt,
256                                  uint32_t type, uint32_t cfval) const
257{
258    enum ArmShiftType shiftType;
259    shiftType = (enum ArmShiftType) type;
260
261    if (shamt == 0)
262        return cfval;
263
264    switch (shiftType)
265    {
266      case LSL:
267        if (shamt > 32)
268            return 0;
269        else
270            return (base >> (32 - shamt)) & 1;
271      case LSR:
272        if (shamt > 32)
273            return 0;
274        else
275            return (base >> (shamt - 1)) & 1;
276      case ASR:
277        if (shamt > 32)
278            shamt = 32;
279        return (base >> (shamt - 1)) & 1;
280      case ROR:
281        shamt = shamt & 0x1f;
282        if (shamt == 0)
283            shamt = 32;
284        return (base >> (shamt - 1)) & 1;
285      default:
286        ccprintf(std::cerr, "Unhandled shift type\n");
287        exit(1);
288        break;
289    }
290    return 0;
291}
292
293
294void
295ArmStaticInst::printReg(std::ostream &os, int reg) const
296{
297    RegIndex rel_reg;
298
299    switch (regIdxToClass(reg, &rel_reg)) {
300      case IntRegClass:
301        if (aarch64) {
302            if (reg == INTREG_UREG0)
303                ccprintf(os, "ureg0");
304            else if (reg == INTREG_SPX)
305               ccprintf(os, "%s%s", (intWidth == 32) ? "w" : "", "sp");
306            else if (reg == INTREG_X31)
307                ccprintf(os, "%szr", (intWidth == 32) ? "w" : "x");
308            else
309                ccprintf(os, "%s%d", (intWidth == 32) ? "w" : "x", reg);
310        } else {
311            switch (rel_reg) {
312              case PCReg:
313                ccprintf(os, "pc");
314                break;
315              case StackPointerReg:
316                ccprintf(os, "sp");
317                break;
318              case FramePointerReg:
319                ccprintf(os, "fp");
320                break;
321              case ReturnAddressReg:
322                ccprintf(os, "lr");
323                break;
324              default:
325                ccprintf(os, "r%d", reg);
326                break;
327            }
328        }
329        break;
330      case FloatRegClass:
331        ccprintf(os, "f%d", rel_reg);
332        break;
333      case MiscRegClass:
334        assert(rel_reg < NUM_MISCREGS);
335        ccprintf(os, "%s", ArmISA::miscRegName[rel_reg]);
336        break;
337      case CCRegClass:
338        ccprintf(os, "cc_%s", ArmISA::ccRegName[rel_reg]);
339        break;
340    }
341}
342
343void
344ArmStaticInst::printMnemonic(std::ostream &os,
345                             const std::string &suffix,
346                             bool withPred,
347                             bool withCond64,
348                             ConditionCode cond64) const
349{
350    os << "  " << mnemonic;
351    if (withPred && !aarch64) {
352        printCondition(os, machInst.condCode);
353        os << suffix;
354    } else if (withCond64) {
355        os << ".";
356        printCondition(os, cond64);
357        os << suffix;
358    }
359    if (machInst.bigThumb)
360        os << ".w";
361    os << "   ";
362}
363
364void
365ArmStaticInst::printTarget(std::ostream &os, Addr target,
366                           const SymbolTable *symtab) const
367{
368    Addr symbolAddr;
369    std::string symbol;
370
371    if (symtab && symtab->findNearestSymbol(target, symbol, symbolAddr)) {
372        ccprintf(os, "<%s", symbol);
373        if (symbolAddr != target)
374            ccprintf(os, "+%d>", target - symbolAddr);
375        else
376            ccprintf(os, ">");
377    } else {
378        ccprintf(os, "%#x", target);
379    }
380}
381
382void
383ArmStaticInst::printCondition(std::ostream &os,
384                              unsigned code,
385                              bool noImplicit) const
386{
387    switch (code) {
388      case COND_EQ:
389        os << "eq";
390        break;
391      case COND_NE:
392        os << "ne";
393        break;
394      case COND_CS:
395        os << "cs";
396        break;
397      case COND_CC:
398        os << "cc";
399        break;
400      case COND_MI:
401        os << "mi";
402        break;
403      case COND_PL:
404        os << "pl";
405        break;
406      case COND_VS:
407        os << "vs";
408        break;
409      case COND_VC:
410        os << "vc";
411        break;
412      case COND_HI:
413        os << "hi";
414        break;
415      case COND_LS:
416        os << "ls";
417        break;
418      case COND_GE:
419        os << "ge";
420        break;
421      case COND_LT:
422        os << "lt";
423        break;
424      case COND_GT:
425        os << "gt";
426        break;
427      case COND_LE:
428        os << "le";
429        break;
430      case COND_AL:
431        // This one is implicit.
432        if (noImplicit)
433            os << "al";
434        break;
435      case COND_UC:
436        // Unconditional.
437        if (noImplicit)
438            os << "uc";
439        break;
440      default:
441        panic("Unrecognized condition code %d.\n", code);
442    }
443}
444
445void
446ArmStaticInst::printMemSymbol(std::ostream &os,
447                              const SymbolTable *symtab,
448                              const std::string &prefix,
449                              const Addr addr,
450                              const std::string &suffix) const
451{
452    Addr symbolAddr;
453    std::string symbol;
454    if (symtab && symtab->findNearestSymbol(addr, symbol, symbolAddr)) {
455        ccprintf(os, "%s%s", prefix, symbol);
456        if (symbolAddr != addr)
457            ccprintf(os, "+%d", addr - symbolAddr);
458        ccprintf(os, suffix);
459    }
460}
461
462void
463ArmStaticInst::printShiftOperand(std::ostream &os,
464                                     IntRegIndex rm,
465                                     bool immShift,
466                                     uint32_t shiftAmt,
467                                     IntRegIndex rs,
468                                     ArmShiftType type) const
469{
470    bool firstOp = false;
471
472    if (rm != INTREG_ZERO) {
473        printReg(os, rm);
474    }
475
476    bool done = false;
477
478    if ((type == LSR || type == ASR) && immShift && shiftAmt == 0)
479        shiftAmt = 32;
480
481    switch (type) {
482      case LSL:
483        if (immShift && shiftAmt == 0) {
484            done = true;
485            break;
486        }
487        if (!firstOp)
488            os << ", ";
489        os << "LSL";
490        break;
491      case LSR:
492        if (!firstOp)
493            os << ", ";
494        os << "LSR";
495        break;
496      case ASR:
497        if (!firstOp)
498            os << ", ";
499        os << "ASR";
500        break;
501      case ROR:
502        if (immShift && shiftAmt == 0) {
503            if (!firstOp)
504                os << ", ";
505            os << "RRX";
506            done = true;
507            break;
508        }
509        if (!firstOp)
510            os << ", ";
511        os << "ROR";
512        break;
513      default:
514        panic("Tried to disassemble unrecognized shift type.\n");
515    }
516    if (!done) {
517        if (!firstOp)
518            os << " ";
519        if (immShift)
520            os << "#" << shiftAmt;
521        else
522            printReg(os, rs);
523    }
524}
525
526void
527ArmStaticInst::printExtendOperand(bool firstOperand, std::ostream &os,
528                                  IntRegIndex rm, ArmExtendType type,
529                                  int64_t shiftAmt) const
530{
531    if (!firstOperand)
532        ccprintf(os, ", ");
533    printReg(os, rm);
534    if (type == UXTX && shiftAmt == 0)
535        return;
536    switch (type) {
537      case UXTB: ccprintf(os, ", UXTB");
538        break;
539      case UXTH: ccprintf(os, ", UXTH");
540        break;
541      case UXTW: ccprintf(os, ", UXTW");
542        break;
543      case UXTX: ccprintf(os, ", LSL");
544        break;
545      case SXTB: ccprintf(os, ", SXTB");
546        break;
547      case SXTH: ccprintf(os, ", SXTH");
548        break;
549      case SXTW: ccprintf(os, ", SXTW");
550        break;
551      case SXTX: ccprintf(os, ", SXTW");
552        break;
553    }
554    if (type == UXTX || shiftAmt)
555        ccprintf(os, " #%d", shiftAmt);
556}
557
558void
559ArmStaticInst::printDataInst(std::ostream &os, bool withImm,
560        bool immShift, bool s, IntRegIndex rd, IntRegIndex rn,
561        IntRegIndex rm, IntRegIndex rs, uint32_t shiftAmt,
562        ArmShiftType type, uint64_t imm) const
563{
564    printMnemonic(os, s ? "s" : "");
565    bool firstOp = true;
566
567    // Destination
568    if (rd != INTREG_ZERO) {
569        firstOp = false;
570        printReg(os, rd);
571    }
572
573    // Source 1.
574    if (rn != INTREG_ZERO) {
575        if (!firstOp)
576            os << ", ";
577        firstOp = false;
578        printReg(os, rn);
579    }
580
581    if (!firstOp)
582        os << ", ";
583    if (withImm) {
584        ccprintf(os, "#%ld", imm);
585    } else {
586        printShiftOperand(os, rm, immShift, shiftAmt, rs, type);
587    }
588}
589
590std::string
591ArmStaticInst::generateDisassembly(Addr pc,
592                                   const SymbolTable *symtab) const
593{
594    std::stringstream ss;
595    printMnemonic(ss);
596    return ss.str();
597}
598
599
600Fault
601ArmStaticInst::advSIMDFPAccessTrap64(ExceptionLevel el) const
602{
603    switch (el) {
604      case EL1:
605        return std::make_shared<SupervisorTrap>(machInst, 0x1E00000,
606                                                EC_TRAPPED_SIMD_FP);
607      case EL2:
608        return std::make_shared<HypervisorTrap>(machInst, 0x1E00000,
609                                                EC_TRAPPED_SIMD_FP);
610      case EL3:
611        return std::make_shared<SecureMonitorTrap>(machInst, 0x1E00000,
612                                                   EC_TRAPPED_SIMD_FP);
613
614      default:
615        panic("Illegal EL in advSIMDFPAccessTrap64\n");
616    }
617}
618
619
620Fault
621ArmStaticInst::checkFPAdvSIMDTrap64(ThreadContext *tc, CPSR cpsr) const
622{
623    const ExceptionLevel el = (ExceptionLevel) (uint8_t)cpsr.el;
624
625    if (ArmSystem::haveVirtualization(tc) && el <= EL2) {
626        HCPTR cptrEnCheck = tc->readMiscReg(MISCREG_CPTR_EL2);
627        if (cptrEnCheck.tfp)
628            return advSIMDFPAccessTrap64(EL2);
629    }
630
631    if (ArmSystem::haveSecurity(tc)) {
632        HCPTR cptrEnCheck = tc->readMiscReg(MISCREG_CPTR_EL3);
633        if (cptrEnCheck.tfp)
634            return advSIMDFPAccessTrap64(EL3);
635    }
636
637    return NoFault;
638}
639
640Fault
641ArmStaticInst::checkFPAdvSIMDEnabled64(ThreadContext *tc,
642                                       CPSR cpsr, CPACR cpacr) const
643{
644    const ExceptionLevel el = (ExceptionLevel) (uint8_t)cpsr.el;
645    if ((el == EL0 && cpacr.fpen != 0x3) ||
646        (el == EL1 && !(cpacr.fpen & 0x1)))
647        return advSIMDFPAccessTrap64(EL1);
648
649    return checkFPAdvSIMDTrap64(tc, cpsr);
650}
651
652Fault
653ArmStaticInst::checkAdvSIMDOrFPEnabled32(ThreadContext *tc,
654                                         CPSR cpsr, CPACR cpacr,
655                                         NSACR nsacr, FPEXC fpexc,
656                                         bool fpexc_check, bool advsimd) const
657{
658    const bool have_virtualization = ArmSystem::haveVirtualization(tc);
659    const bool have_security = ArmSystem::haveSecurity(tc);
660    const bool is_secure = inSecureState(tc);
661    const ExceptionLevel cur_el = opModeToEL(currOpMode(tc));
662
663    if (cur_el == EL0 && ELIs64(tc, EL1))
664        return checkFPAdvSIMDEnabled64(tc, cpsr, cpacr);
665
666    uint8_t cpacr_cp10 = cpacr.cp10;
667    bool cpacr_asedis = cpacr.asedis;
668
669    if (have_security && !ELIs64(tc, EL3) && !is_secure) {
670        if (nsacr.nsasedis)
671            cpacr_asedis = true;
672        if (nsacr.cp10 == 0)
673            cpacr_cp10 = 0;
674    }
675
676    if (cur_el != EL2) {
677        if (advsimd && cpacr_asedis)
678            return disabledFault();
679
680        if ((cur_el == EL0 && cpacr_cp10 != 0x3) ||
681            (cur_el != EL0 && !(cpacr_cp10 & 0x1)))
682            return disabledFault();
683    }
684
685    if (fpexc_check && !fpexc.en)
686        return disabledFault();
687
688    // -- aarch32/exceptions/traps/AArch32.CheckFPAdvSIMDTrap --
689
690    if (have_virtualization && !is_secure && ELIs64(tc, EL2))
691        return checkFPAdvSIMDTrap64(tc, cpsr);
692
693    if (have_virtualization && !is_secure) {
694        HCPTR hcptr = tc->readMiscReg(MISCREG_HCPTR);
695        bool hcptr_cp10 = hcptr.tcp10;
696        bool hcptr_tase = hcptr.tase;
697
698        if (have_security && !ELIs64(tc, EL3) && !is_secure) {
699            if (nsacr.nsasedis)
700                hcptr_tase = true;
701            if (nsacr.cp10)
702                hcptr_cp10 = true;
703        }
704
705        if ((advsimd && hcptr_tase) || hcptr_cp10) {
706            const uint32_t iss = advsimd ? (1 << 5) : 0xA;
707            if (cur_el == EL2) {
708                return std::make_shared<UndefinedInstruction>(
709                    machInst, iss,
710                    EC_TRAPPED_HCPTR, mnemonic);
711            } else {
712                return std::make_shared<HypervisorTrap>(
713                    machInst, iss,
714                    EC_TRAPPED_HCPTR);
715            }
716
717        }
718    }
719
720    if (have_security && ELIs64(tc, EL3)) {
721        HCPTR cptrEnCheck = tc->readMiscReg(MISCREG_CPTR_EL3);
722        if (cptrEnCheck.tfp)
723            return advSIMDFPAccessTrap64(EL3);
724    }
725
726    return NoFault;
727}
728
729
730}
731