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 
39 ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info)
40 {
41     ocsd_err_t err = OCSD_OK;
42     clear_instr_subtype();
43     switch(instr_info->isa)
44     {
45     case ocsd_isa_arm:
46         err = DecodeA32(instr_info);
47         break;
48 
49     case ocsd_isa_thumb2:
50         err = DecodeT32(instr_info);
51         break;
52 
53     case ocsd_isa_aarch64:
54         err = DecodeA64(instr_info);
55         break;
56 
57     case ocsd_isa_tee:
58     case ocsd_isa_jazelle:
59     default:
60         // unsupported ISA
61         err = OCSD_ERR_UNSUPPORTED_ISA;
62         break;
63     }
64     instr_info->sub_type = get_instr_subtype();
65     return err;
66 }
67 
68 ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info)
69 {
70     uint32_t branchAddr = 0;
71     arm_barrier_t barrier;
72 
73     instr_info->instr_size = 4; // instruction size A32
74     instr_info->type =  OCSD_INSTR_OTHER;  // default type
75     instr_info->next_isa = instr_info->isa; // assume same ISA
76     instr_info->is_link = 0;
77 
78     if(inst_ARM_is_indirect_branch(instr_info->opcode))
79     {
80         instr_info->type = OCSD_INSTR_BR_INDIRECT;
81         instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode);
82     }
83     else if(inst_ARM_is_direct_branch(instr_info->opcode))
84     {
85         inst_ARM_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
86         instr_info->type = OCSD_INSTR_BR;
87         if (branchAddr & 0x1)
88         {
89             instr_info->next_isa = ocsd_isa_thumb2;
90             branchAddr &= ~0x1;
91         }
92         instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
93         instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode);
94     }
95     else if((barrier = inst_ARM_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
96     {
97         switch(barrier)
98         {
99         case ARM_BARRIER_ISB:
100             instr_info->type = OCSD_INSTR_ISB;
101             break;
102 
103         case ARM_BARRIER_DSB:
104         case ARM_BARRIER_DMB:
105             if(instr_info->dsb_dmb_waypoints)
106                 instr_info->type = OCSD_INSTR_DSB_DMB;
107             break;
108         }
109     }
110 
111     instr_info->is_conditional = inst_ARM_is_conditional(instr_info->opcode);
112 
113     return OCSD_OK;
114 }
115 
116 ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info)
117 {
118     uint64_t branchAddr = 0;
119     arm_barrier_t barrier;
120 
121     instr_info->instr_size =  4; // default address update
122     instr_info->type =  OCSD_INSTR_OTHER;  // default type
123     instr_info->next_isa = instr_info->isa; // assume same ISA
124     instr_info->is_link = 0;
125 
126     if(inst_A64_is_indirect_branch(instr_info->opcode))
127     {
128         instr_info->type = OCSD_INSTR_BR_INDIRECT;
129         instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode);
130     }
131     else if(inst_A64_is_direct_branch(instr_info->opcode))
132     {
133         inst_A64_branch_destination(instr_info->instr_addr,instr_info->opcode,&branchAddr);
134         instr_info->type = OCSD_INSTR_BR;
135         instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
136         instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode);
137     }
138     else if((barrier = inst_A64_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
139     {
140         switch(barrier)
141         {
142         case ARM_BARRIER_ISB:
143             instr_info->type = OCSD_INSTR_ISB;
144             break;
145 
146         case ARM_BARRIER_DSB:
147         case ARM_BARRIER_DMB:
148             if(instr_info->dsb_dmb_waypoints)
149                 instr_info->type = OCSD_INSTR_DSB_DMB;
150             break;
151         }
152     }
153 
154     instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode);
155 
156     return OCSD_OK;
157 }
158 
159 ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info)
160 {
161     uint32_t branchAddr = 0;
162     arm_barrier_t barrier;
163 
164     // need to align the 32 bit opcode as 2 16 bit, with LS 16 as in top 16 bit of
165     // 32 bit word - T2 routines assume 16 bit in top 16 bit of 32 bit opcode.
166     uint32_t op_temp = (instr_info->opcode >> 16) & 0xFFFF;
167     op_temp |= ((instr_info->opcode & 0xFFFF) << 16);
168     instr_info->opcode = op_temp;
169 
170 
171     instr_info->instr_size = is_wide_thumb((uint16_t)(instr_info->opcode >> 16)) ? 4 : 2;
172     instr_info->type =  OCSD_INSTR_OTHER;  // default type
173     instr_info->next_isa = instr_info->isa; // assume same ISA
174     instr_info->is_link = 0;
175 
176     if(inst_Thumb_is_indirect_branch(instr_info->opcode))
177     {
178         instr_info->type = OCSD_INSTR_BR_INDIRECT;
179         instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode);
180     }
181     else if(inst_Thumb_is_direct_branch(instr_info->opcode))
182     {
183         inst_Thumb_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
184         instr_info->type = OCSD_INSTR_BR;
185         instr_info->branch_addr = (ocsd_vaddr_t)(branchAddr & ~0x1);
186         if((branchAddr & 0x1) == 0)
187             instr_info->next_isa = ocsd_isa_arm;
188         instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode);
189     }
190     else if((barrier = inst_Thumb_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
191     {
192         switch(barrier)
193         {
194         case ARM_BARRIER_ISB:
195             instr_info->type = OCSD_INSTR_ISB;
196             break;
197 
198         case ARM_BARRIER_DSB:
199         case ARM_BARRIER_DMB:
200             if(instr_info->dsb_dmb_waypoints)
201                 instr_info->type = OCSD_INSTR_DSB_DMB;
202             break;
203         }
204     }
205 
206     instr_info->is_conditional = inst_Thumb_is_conditional(instr_info->opcode);
207     instr_info->thumb_it_conditions = inst_Thumb_is_IT(instr_info->opcode);
208 
209     return OCSD_OK;
210 }
211 
212 
213 /* End of File trc_i_decode.cpp */
214