1/*
2 * \file       trc_i_decode.cpp
3 * \brief      OpenCSD :
4 *
5 * \copyright  Copyright (c) 2015, ARM Limited. All Rights Reserved.
6 */
7
8/*
9 * Redistribution and use in source and binary forms, with or without modification,
10 * are permitted provided that the following conditions are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the copyright holder nor the names of its contributors
20 * may be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "opencsd/ocsd_if_types.h"
36#include "i_dec/trc_i_decode.h"
37#include "i_dec/trc_idec_arminst.h"
38
39ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info)
40{
41    ocsd_err_t err = OCSD_OK;
42    struct decode_info info;
43
44    info.instr_sub_type = OCSD_S_INSTR_NONE;
45    info.arch_version = (uint16_t)(instr_info->pe_type.arch);
46
47    switch(instr_info->isa)
48    {
49    case ocsd_isa_arm:
50        err = DecodeA32(instr_info, &info);
51        break;
52
53    case ocsd_isa_thumb2:
54        err = DecodeT32(instr_info, &info);
55        break;
56
57    case ocsd_isa_aarch64:
58        err = DecodeA64(instr_info, &info);
59        break;
60
61    case ocsd_isa_tee:
62    case ocsd_isa_jazelle:
63    default:
64        // unsupported ISA
65        err = OCSD_ERR_UNSUPPORTED_ISA;
66        break;
67    }
68    instr_info->sub_type = info.instr_sub_type;
69    return err;
70}
71
72ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info, struct decode_info *info)
73{
74    uint32_t branchAddr = 0;
75    arm_barrier_t barrier;
76
77    instr_info->instr_size = 4; // instruction size A32
78    instr_info->type =  OCSD_INSTR_OTHER;  // default type
79    instr_info->next_isa = instr_info->isa; // assume same ISA
80    instr_info->is_link = 0;
81
82    if(inst_ARM_is_indirect_branch(instr_info->opcode, info))
83    {
84        instr_info->type = OCSD_INSTR_BR_INDIRECT;
85        instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info);
86    }
87    else if(inst_ARM_is_direct_branch(instr_info->opcode))
88    {
89        inst_ARM_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
90        instr_info->type = OCSD_INSTR_BR;
91        if (branchAddr & 0x1)
92        {
93            instr_info->next_isa = ocsd_isa_thumb2;
94            branchAddr &= ~0x1;
95        }
96        instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
97        instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info);
98    }
99    else if((barrier = inst_ARM_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
100    {
101        switch(barrier)
102        {
103        case ARM_BARRIER_ISB:
104            instr_info->type = OCSD_INSTR_ISB;
105            break;
106
107        case ARM_BARRIER_DSB:
108        case ARM_BARRIER_DMB:
109            if(instr_info->dsb_dmb_waypoints)
110                instr_info->type = OCSD_INSTR_DSB_DMB;
111            break;
112        }
113    }
114    else if (instr_info->wfi_wfe_branch)
115    {
116        if (inst_ARM_wfiwfe(instr_info->opcode))
117        {
118            instr_info->type = OCSD_INSTR_WFI_WFE;
119        }
120    }
121    instr_info->is_conditional = inst_ARM_is_conditional(instr_info->opcode);
122
123    return OCSD_OK;
124}
125
126ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info, struct decode_info *info)
127{
128    uint64_t branchAddr = 0;
129    arm_barrier_t barrier;
130
131    instr_info->instr_size =  4; // default address update
132    instr_info->type =  OCSD_INSTR_OTHER;  // default type
133    instr_info->next_isa = instr_info->isa; // assume same ISA
134    instr_info->is_link = 0;
135
136    if(inst_A64_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info))
137    {
138        instr_info->type = OCSD_INSTR_BR_INDIRECT;
139//        instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode);
140    }
141    else if(inst_A64_is_direct_branch_link(instr_info->opcode, &instr_info->is_link, info))
142    {
143        inst_A64_branch_destination(instr_info->instr_addr,instr_info->opcode,&branchAddr);
144        instr_info->type = OCSD_INSTR_BR;
145        instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
146//        instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode);
147    }
148    else if((barrier = inst_A64_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
149    {
150        switch(barrier)
151        {
152        case ARM_BARRIER_ISB:
153            instr_info->type = OCSD_INSTR_ISB;
154            break;
155
156        case ARM_BARRIER_DSB:
157        case ARM_BARRIER_DMB:
158            if(instr_info->dsb_dmb_waypoints)
159                instr_info->type = OCSD_INSTR_DSB_DMB;
160            break;
161        }
162    }
163    else if (instr_info->wfi_wfe_branch)
164    {
165        if (inst_A64_wfiwfe(instr_info->opcode))
166        {
167            instr_info->type = OCSD_INSTR_WFI_WFE;
168        }
169    }
170
171    instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode);
172
173    return OCSD_OK;
174}
175
176ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info, struct decode_info *info)
177{
178    uint32_t branchAddr = 0;
179    arm_barrier_t barrier;
180
181    // need to align the 32 bit opcode as 2 16 bit, with LS 16 as in top 16 bit of
182    // 32 bit word - T2 routines assume 16 bit in top 16 bit of 32 bit opcode.
183    uint32_t op_temp = (instr_info->opcode >> 16) & 0xFFFF;
184    op_temp |= ((instr_info->opcode & 0xFFFF) << 16);
185    instr_info->opcode = op_temp;
186
187
188    instr_info->instr_size = is_wide_thumb((uint16_t)(instr_info->opcode >> 16)) ? 4 : 2;
189    instr_info->type =  OCSD_INSTR_OTHER;  // default type
190    instr_info->next_isa = instr_info->isa; // assume same ISA
191    instr_info->is_link = 0;
192    instr_info->is_conditional = 0;
193
194
195    if(inst_Thumb_is_direct_branch_link(instr_info->opcode,&instr_info->is_link, &instr_info->is_conditional, info))
196    {
197        inst_Thumb_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
198        instr_info->type = OCSD_INSTR_BR;
199        instr_info->branch_addr = (ocsd_vaddr_t)(branchAddr & ~0x1);
200        if((branchAddr & 0x1) == 0)
201            instr_info->next_isa = ocsd_isa_arm;
202    }
203    else if (inst_Thumb_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info))
204    {
205        instr_info->type = OCSD_INSTR_BR_INDIRECT;
206    }
207    else if((barrier = inst_Thumb_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
208    {
209        switch(barrier)
210        {
211        case ARM_BARRIER_ISB:
212            instr_info->type = OCSD_INSTR_ISB;
213            break;
214
215        case ARM_BARRIER_DSB:
216        case ARM_BARRIER_DMB:
217            if(instr_info->dsb_dmb_waypoints)
218                instr_info->type = OCSD_INSTR_DSB_DMB;
219            break;
220        }
221    }
222    else if (instr_info->wfi_wfe_branch)
223    {
224        if (inst_Thumb_wfiwfe(instr_info->opcode))
225        {
226            instr_info->type = OCSD_INSTR_WFI_WFE;
227        }
228    }
229    instr_info->is_conditional = inst_Thumb_is_conditional(instr_info->opcode);
230    instr_info->thumb_it_conditions = inst_Thumb_is_IT(instr_info->opcode);
231
232    return OCSD_OK;
233}
234
235/* End of File trc_i_decode.cpp */
236