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