• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * \file       ext_dcd_echo_test_fact.c
3 * \brief      OpenCSD : Echo test custom decoder factory
4 *
5 * \copyright  Copyright (c) 2016, 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 <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "opencsd/c_api/opencsd_c_api.h"
40 #include "opencsd/c_api/ocsd_c_api_types.h"
41 #include "opencsd/c_api/ocsd_c_api_cust_impl.h"
42 
43 #include "ext_dcd_echo_test_fact.h"
44 #include "ext_dcd_echo_test.h"
45 
46 /** The name of the decoder */
47 #define DECODER_NAME "ECHO_TEST"
48 
49 /********* External callback fns passed to library *****/
50 /** Declare the trace data input function for the decoder - passed to library as call-back. */
51 static ocsd_datapath_resp_t echo_dcd_trace_data_in(const void *decoder_handle,
52     const ocsd_datapath_op_t op,
53     const ocsd_trc_index_t index,
54     const uint32_t dataBlockSize,
55     const uint8_t *pDataBlock,
56     uint32_t *numBytesProcessed);
57 
58 /** Allow library to update the packet monitor / sink in use flags to allow decoder to call CB as appropriate.*/
59 static void echo_dcd_update_mon_flags(const void *decoder_handle, const int flags);
60 
61 /********* Fns called by decoder creation factory  *****/
62 void echo_dcd_init(echo_decoder_t *decoder,
63     ocsd_extern_dcd_inst_t *p_decoder_inst,
64     const echo_dcd_cfg_t *p_config,
65     const ocsd_extern_dcd_cb_fns *p_lib_callbacks);
66 
67 void echo_dcd_pkt_tostr(echo_dcd_pkt_t *pkt, char *buffer, const int buflen);
68 
69 /********* Internal decoder functions  *****/
70 static void echo_dcd_reset(echo_decoder_t *decoder);
71 static ocsd_datapath_resp_t echo_dcd_process_data(echo_decoder_t *decoder,
72     const ocsd_trc_index_t index,
73     const uint32_t dataBlockSize,
74     const uint8_t *pDataBlock,
75     uint32_t *numBytesProcessed);
76 
77 static ocsd_datapath_resp_t send_gen_packet(echo_decoder_t *decoder);
78 static ocsd_datapath_resp_t analyse_packet(echo_decoder_t *decoder);
79 static ocsd_datapath_resp_t send_none_data_op(echo_decoder_t *decoder, const ocsd_datapath_op_t op);
80 static void print_init_test_message(echo_decoder_t *decoder);
81 
82 /******Infrastructure testing functionality *********************/
83 /* As this is a test decoder we want to check which of the callbacks or call-ins are covered for a given test run
84   (by definition they can't all be - so will need a couple of runs to test all)
85 */
86 enum {
87     TEST_COV_ERRORLOG_CB = 0,
88     TEST_COV_MSGLOG_CB,
89     TEST_COV_GEN_ELEM_CB,
90     TEST_COV_IDEC_CB,
91     TEST_COV_MEM_ACC_CB,
92     TEST_COV_PKTMON_CB,
93     TEST_COV_PKTSINK_CB,
94     TEST_COV_INDATA,
95     TEST_COV_INCBFLAGS,
96     /**/
97     TEST_COV_END
98 };
99 
100 typedef enum {
101     TEST_RES_NA,    /* not tested */
102     TEST_RES_OK,    /* test OK */
103     TEST_RES_FAIL   /* test fail */
104 } test_result_t;
105 
106 static test_result_t coverage[TEST_COV_END] = { TEST_RES_NA };
107 
108 #define UPDATE_COVERAGE(i,r) { if(coverage[i] != TEST_RES_FAIL) coverage[i] = r; }
109 
110 static void print_test_cov_results(echo_decoder_t *decoder);
111 
112 /*************************/
113 
114 
115 /** init decoder on creation, along with library instance structure */
echo_dcd_init(echo_decoder_t * decoder,ocsd_extern_dcd_inst_t * p_decoder_inst,const echo_dcd_cfg_t * p_config,const ocsd_extern_dcd_cb_fns * p_lib_callbacks)116 void echo_dcd_init(echo_decoder_t *decoder, ocsd_extern_dcd_inst_t *p_decoder_inst, const echo_dcd_cfg_t *p_config, const ocsd_extern_dcd_cb_fns *p_lib_callbacks)
117 {
118     // initialise the decoder instance.
119 
120     // zero out the structure
121     memset(decoder, 0, sizeof(echo_decoder_t));
122 
123     memcpy(&(decoder->reg_config), p_config, sizeof(echo_dcd_cfg_t));       // copy in the config structure.
124     memcpy(&(decoder->lib_fns), p_lib_callbacks, sizeof(ocsd_extern_dcd_cb_fns));  // copy in the the library callbacks.
125 
126     echo_dcd_reset(decoder);
127 
128     // fill out the info to pass back to the library.
129 
130     // set up the decoder handle, name and CS Trace ID
131     p_decoder_inst->decoder_handle = decoder;
132     p_decoder_inst->p_decoder_name = DECODER_NAME;
133     p_decoder_inst->cs_id = p_config->cs_id;
134 
135     // set up the data input callback
136     p_decoder_inst->fn_data_in = echo_dcd_trace_data_in;
137     p_decoder_inst->fn_update_pkt_mon = echo_dcd_update_mon_flags;
138 
139 }
140 
echo_dcd_pkt_tostr(echo_dcd_pkt_t * pkt,char * buffer,const int buflen)141 void echo_dcd_pkt_tostr(echo_dcd_pkt_t *pkt, char *buffer, const int buflen)
142 {
143     snprintf(buffer, buflen, "ECHOTP{%d} [0x%02X] (0x%08X)", pkt->header & 0x3, pkt->header, pkt->data);
144 }
145 
146 /**** Main decoder implementation ****/
echo_dcd_trace_data_in(const void * decoder_handle,const ocsd_datapath_op_t op,const ocsd_trc_index_t index,const uint32_t dataBlockSize,const uint8_t * pDataBlock,uint32_t * numBytesProcessed)147 ocsd_datapath_resp_t echo_dcd_trace_data_in(const void *decoder_handle,
148     const ocsd_datapath_op_t op,
149     const ocsd_trc_index_t index,
150     const uint32_t dataBlockSize,
151     const uint8_t *pDataBlock,
152     uint32_t *numBytesProcessed)
153 {
154     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
155     echo_decoder_t *decoder = (echo_decoder_t *)decoder_handle;
156     UPDATE_COVERAGE(TEST_COV_INDATA,TEST_RES_OK)
157 
158     /* Deal with each possible datapath operation.
159     */
160     switch (op)
161     {
162     case OCSD_OP_DATA:
163         resp = echo_dcd_process_data(decoder, index, dataBlockSize, pDataBlock, numBytesProcessed);
164         break;
165 
166     case OCSD_OP_EOT:
167         if (decoder->data_in_count > 0)
168             lib_cb_LogError(&(decoder->lib_fns), OCSD_ERR_SEV_WARN, OCSD_ERR_PKT_INTERP_FAIL,decoder->curr_pkt_idx,decoder->reg_config.cs_id,"Incomplete packet at end of trace.\n");
169 
170         /* if we are in full decoder mode then generate a generic EOT packet. */
171         if (decoder->createFlags &  OCSD_CREATE_FLG_FULL_DECODER)
172         {
173             ocsd_gen_elem_init(&(decoder->out_pkt), OCSD_GEN_TRC_ELEM_EO_TRACE);
174             resp = send_gen_packet(decoder);
175             send_none_data_op(decoder, OCSD_OP_EOT); /* send EOT to any packet monitor in use */
176         }
177         else
178             resp = send_none_data_op(decoder, OCSD_OP_EOT); /*send EOT to packet sink and any packet monitor in use */
179         print_test_cov_results(decoder);    /* end of test run - need to print out the coverage data */
180         break;
181 
182     case OCSD_OP_FLUSH:
183         /* This decoder never saves a list of incoming packets (which some real decoders may have to according to protocol).
184            Additionally this decoder both processes packets and analyses them so there is no second stage to pass the flush request on to.
185            Therefore there is nothing to flush */
186         break;
187 
188     case OCSD_OP_RESET:
189         echo_dcd_reset(decoder);
190         break;
191     }
192     return resp;
193 }
194 
echo_dcd_update_mon_flags(const void * decoder_handle,const int flags)195 void echo_dcd_update_mon_flags(const void *decoder_handle, const int flags)
196 {
197     lib_cb_updatePktCBFlags(&((echo_decoder_t *)decoder_handle)->lib_fns, flags);
198     UPDATE_COVERAGE(TEST_COV_INCBFLAGS,TEST_RES_OK)
199 }
200 
echo_dcd_reset(echo_decoder_t * decoder)201 void echo_dcd_reset(echo_decoder_t *decoder)
202 {
203     decoder->curr_pkt.header = 0;
204     decoder->data_in_count = 0;
205     decoder->state = DCD_INIT;
206 }
207 
echo_dcd_process_data(echo_decoder_t * decoder,const ocsd_trc_index_t index,const uint32_t dataBlockSize,const uint8_t * pDataBlock,uint32_t * numBytesProcessed)208 ocsd_datapath_resp_t echo_dcd_process_data(echo_decoder_t *decoder,
209     const ocsd_trc_index_t index,
210     const uint32_t dataBlockSize,
211     const uint8_t *pDataBlock,
212     uint32_t *numBytesProcessed)
213 {
214     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
215     uint32_t bytesUsed = 0;
216 
217     while (OCSD_DATA_RESP_IS_CONT(resp) && (bytesUsed < dataBlockSize))
218     {
219         switch (decoder->state)
220         {
221 
222         case DCD_INIT:
223             /* on initialisation / after reset output a not-synced indicator */
224             ocsd_gen_elem_init(&decoder->out_pkt, OCSD_GEN_TRC_ELEM_NO_SYNC);
225             resp = send_gen_packet(decoder);
226             decoder->state = DCD_WAIT_SYNC; /* wait for the first sync point */
227             print_init_test_message(decoder);  /* because this is in fact a test decoder - print verification messages */
228             break;
229 
230         case DCD_WAIT_SYNC:
231             /* In this 'protocol' sync will be a single 0x00 byte.
232                Some decoders may output "unsynced packets" markers if in packet processing only mode, or on the
233                packet monitor output if in use. We are not bothering here. */
234             if (pDataBlock[bytesUsed] == 0x00)
235                 decoder->state = DCD_PROC_PACKETS;
236             bytesUsed++;
237             break;
238 
239         case DCD_PROC_PACKETS:
240             /* collect our ECHO_DCD_PKT_SIZE byte packets into the data in buffer */
241             if (decoder->data_in_count < ECHO_DCD_PKT_SIZE)
242             {
243                 if (decoder->data_in_count == 0)
244                     decoder->curr_pkt_idx = index + bytesUsed;  /* record the correct start of packet index in the buffer. */
245                 decoder->data_in[decoder->data_in_count++] = pDataBlock[bytesUsed++];
246             }
247 
248             /* if we have ECHO_DCD_PKT_SIZE bytes we have a packet */
249             if (decoder->data_in_count == ECHO_DCD_PKT_SIZE)
250             {
251                 resp = analyse_packet(decoder);
252                 decoder->data_in_count = 0; /* done with the current packet */
253             }
254             break;
255         }
256     }
257     *numBytesProcessed = bytesUsed;
258     return resp;
259 }
260 
send_gen_packet(echo_decoder_t * decoder)261 ocsd_datapath_resp_t send_gen_packet(echo_decoder_t *decoder)
262 {
263     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
264     /* Only output generic decode packets if we are in full decode mode. */
265     if (decoder->createFlags &  OCSD_CREATE_FLG_FULL_DECODER)
266     {
267         resp = lib_cb_GenElemOp(&decoder->lib_fns, decoder->curr_pkt_idx, decoder->reg_config.cs_id, &decoder->out_pkt);
268         UPDATE_COVERAGE(TEST_COV_GEN_ELEM_CB, (OCSD_DATA_RESP_IS_FATAL(resp) ? TEST_RES_FAIL : TEST_RES_OK))
269     }
270     return resp;
271 }
272 
send_none_data_op(echo_decoder_t * decoder,const ocsd_datapath_op_t op)273 ocsd_datapath_resp_t send_none_data_op(echo_decoder_t *decoder, const ocsd_datapath_op_t op)
274 {
275     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
276     ocsd_extern_dcd_cb_fns *p_fns = &(decoder->lib_fns);
277 
278     /* send a none data op to the packet monitor or packet sink if in packet processing only mode
279        None data ops have the data parameters all set to 0.
280      */
281 
282      /* if the packet monitor callback is in use. */
283     if (lib_cb_usePktMon(p_fns))
284         lib_cb_PktMon(p_fns, op, 0, 0, 0, 0);
285 
286     /* if the packet sink is in use then we shouldn't be in full decoder mode.*/
287     if (lib_cb_usePktSink(p_fns))
288         resp = lib_cb_PktDataSink(p_fns, op, 0, 0);
289 
290     return resp;
291 }
292 
print_init_test_message(echo_decoder_t * decoder)293 void print_init_test_message(echo_decoder_t * decoder)
294 {
295     ocsd_extern_dcd_cb_fns *p_fns = &(decoder->lib_fns);
296     if (lib_cb_LogMsg(p_fns, OCSD_ERR_SEV_ERROR, "Echo_Test_Decoder: Init - LogMsgCB test.\n") == OCSD_OK)
297         UPDATE_COVERAGE(TEST_COV_MSGLOG_CB, TEST_RES_OK)
298     else
299         UPDATE_COVERAGE(TEST_COV_MSGLOG_CB, TEST_RES_FAIL)
300 
301     if(lib_cb_LogError(p_fns, OCSD_ERR_SEV_ERROR, OCSD_OK, 0, decoder->reg_config.cs_id, "Echo_Test_Decoder - Init - LogErrorCB test.\n") == OCSD_OK)
302         UPDATE_COVERAGE(TEST_COV_ERRORLOG_CB, TEST_RES_OK)
303     else
304         UPDATE_COVERAGE(TEST_COV_ERRORLOG_CB, TEST_RES_FAIL)
305 }
306 
print_test_cov_results(echo_decoder_t * decoder)307 void print_test_cov_results(echo_decoder_t *decoder)
308 {
309     int i;
310     ocsd_extern_dcd_cb_fns *p_fns = &(decoder->lib_fns);
311     static char *results[] = {
312         "Not Tested", "Passed", "Failed"
313     };
314     static char *cov_elem_names[] = {
315         "ERRORLOG_CB",
316         "MSGLOG_CB",
317         "GEN_ELEM_CB",
318         "IDEC_CB",
319         "MEM_ACC_CB",
320         "PKTMON_CB",
321         "PKTSINK_CB",
322         "INDATA",
323         "INCBFLAGS"
324     };
325     char coverage_message[256];
326 
327     for (i = 0; i < TEST_COV_END; i++)
328     {
329         sprintf(coverage_message, "Element %s : %s\n",cov_elem_names[i],results[coverage[i]]);
330         if (coverage[TEST_COV_MSGLOG_CB] == TEST_RES_OK)    /* check we can use the msg logger for outputting the results */
331             lib_cb_LogMsg(p_fns, OCSD_ERR_SEV_ERROR, coverage_message);
332         else
333 	  printf("%s", coverage_message);
334     }
335 }
336 
337 
338 /* This is the packet decode portion of the decoder.
339 *  incoming protocol packets are analysed to create generic output packets.
340 */
analyse_packet(echo_decoder_t * decoder)341 ocsd_datapath_resp_t analyse_packet(echo_decoder_t * decoder)
342 {
343     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
344     ocsd_extern_dcd_cb_fns *p_fns = &(decoder->lib_fns);
345     uint32_t num_mem_bytes = 4;
346     uint8_t mem_buffer[4];
347     ocsd_instr_info instr_info;
348     ocsd_err_t err;
349 
350     /* create a packet from the data */
351     decoder->curr_pkt.header = decoder->data_in[0];
352     decoder->curr_pkt.data = *((uint32_t *)&decoder->data_in[1]);
353 
354     /* if the packet monitor callback is in use - output the newly created packet. */
355     if (lib_cb_usePktMon(p_fns))
356     {
357         lib_cb_PktMon(p_fns, OCSD_OP_DATA, decoder->curr_pkt_idx, (const void *)(&decoder->curr_pkt), ECHO_DCD_PKT_SIZE, decoder->data_in);
358         UPDATE_COVERAGE(TEST_COV_PKTMON_CB, TEST_RES_OK)
359     }
360 
361     /* if the packet sink is in use then we shouldn't be in full decoder mode.*/
362     if (lib_cb_usePktSink(p_fns))
363     {
364         resp = lib_cb_PktDataSink(p_fns, OCSD_OP_DATA, decoder->curr_pkt_idx, (const void *)(&decoder->curr_pkt));
365         UPDATE_COVERAGE(TEST_COV_PKTSINK_CB, (OCSD_DATA_RESP_IS_FATAL(resp) ? TEST_RES_FAIL : TEST_RES_OK))
366     }
367     else if (decoder->createFlags &  OCSD_CREATE_FLG_FULL_DECODER) /* no packet sink so are we full decoder? */
368     {
369         /*  Full decode - generate generic output packets.
370 
371             A real decoder will sometimes require multiple input packets per output packet, or may generate multiple output
372             packets per single input packet. Here we stick at 1:1 for test simplicity.
373 
374             This code will also test the infrastructure callbacks to ensure that everything holds together correctly.
375         */
376 
377         /* nominally 4 types of packet */
378         switch (decoder->curr_pkt.header & 0x3)
379         {
380         case 0:
381             ocsd_gen_elem_init(&decoder->out_pkt, OCSD_GEN_TRC_ELEM_CUSTOM);    /* full custom packet */
382             decoder->out_pkt.extended_data = 1;/* mark the extended ptr in use */
383             decoder->out_pkt.ptr_extended_data = decoder->data_in;  /* the custom packet data in this protocol just the packet itself (hence 'echo')*/
384             break;
385 
386         case 1:
387             /* custom decoders can re-use existing packet types if they follow the rules for those types. */
388             ocsd_gen_elem_init(&decoder->out_pkt, OCSD_GEN_TRC_ELEM_INSTR_RANGE);
389             /* fake up an address range using the input data */
390             decoder->out_pkt.st_addr = decoder->curr_pkt.data & 0xFFFFFFF0;
391             decoder->out_pkt.en_addr = decoder->curr_pkt.data + 0x10 + (((uint32_t)decoder->curr_pkt.header) << 2);
392             decoder->out_pkt.isa = ocsd_isa_custom;
393             decoder->out_pkt.last_instr_exec = (decoder->curr_pkt.header & 0x4) ? 1 : 0;
394             break;
395 
396         case 2:
397             /* test the memory access callback. */
398             err = lib_cb_MemAccess(p_fns, decoder->curr_pkt.data & 0xFFFFFFF0, decoder->reg_config.cs_id, OCSD_MEM_SPACE_ANY, &num_mem_bytes, mem_buffer);
399             if (err != OCSD_OK)
400                 lib_cb_LogError(p_fns, OCSD_ERR_SEV_ERROR, err, decoder->curr_pkt_idx, decoder->reg_config.cs_id, "Error accessing memory area\n.");
401             UPDATE_COVERAGE(TEST_COV_MEM_ACC_CB,(err == OCSD_OK ? TEST_RES_OK : TEST_RES_FAIL))
402             if (num_mem_bytes == 0)
403             {
404                 /* unable to read the address... */
405                 ocsd_gen_elem_init(&decoder->out_pkt, OCSD_GEN_TRC_ELEM_ADDR_NACC);
406                 decoder->out_pkt.st_addr = decoder->curr_pkt.data & 0xFFFFFFF0;
407             }
408             else
409             {
410                 /* try something different */
411                 ocsd_gen_elem_init(&decoder->out_pkt, OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
412                 decoder->out_pkt.cycle_count = *((uint32_t *)mem_buffer);
413                 decoder->out_pkt.has_cc = 1;
414             }
415             break;
416 
417         case 3:
418             /* test the ARM instruction decode callback */
419             instr_info.pe_type.arch = ARCH_V8;
420             instr_info.pe_type.profile = profile_CortexA;
421             instr_info.isa = ocsd_isa_aarch64;
422             instr_info.opcode = decoder->curr_pkt.data;
423             instr_info.instr_addr = decoder->curr_pkt.data & 0xFFFFF000;
424             instr_info.dsb_dmb_waypoints = 0;
425 
426             err = lib_cb_DecodeArmInst(p_fns, &instr_info);
427             UPDATE_COVERAGE(TEST_COV_IDEC_CB, (err == OCSD_OK ? TEST_RES_OK : TEST_RES_FAIL))
428             if (err != OCSD_OK)
429             {
430                 lib_cb_LogError(p_fns, OCSD_ERR_SEV_ERROR, err, decoder->curr_pkt_idx, decoder->reg_config.cs_id, "Error decoding instruction\n.");
431                 ocsd_gen_elem_init(&decoder->out_pkt, OCSD_GEN_TRC_ELEM_CUSTOM);
432                 decoder->out_pkt.has_ts = 1;
433                 decoder->out_pkt.timestamp = decoder->curr_pkt.data;
434             }
435             else
436             {
437                 ocsd_gen_elem_init(&decoder->out_pkt, OCSD_GEN_TRC_ELEM_INSTR_RANGE);
438                 /* fake up an address range using the input data */
439                 decoder->out_pkt.st_addr = decoder->curr_pkt.data & 0xFFFFFFF0;
440                 decoder->out_pkt.en_addr = decoder->curr_pkt.data + 0x10 + (((uint32_t)decoder->curr_pkt.header) << 2);
441                 decoder->out_pkt.isa = ocsd_isa_aarch64;
442                 decoder->out_pkt.last_instr_exec = (decoder->curr_pkt.header & 0x4) ? 1 : 0;
443                 decoder->out_pkt.last_i_type = instr_info.type;
444                 decoder->out_pkt.last_i_subtype = instr_info.sub_type;
445             }
446             break;
447         }
448         resp = send_gen_packet(decoder);
449     }
450     return resp;
451 }
452