xref: /aosp_15_r20/external/OpenCSD/decoder/docs/external_custom.md (revision 02ca8ccacfba7e0df68f3332a95f3180334d6649)
1Attaching External Custom Decoders    {#custom_decoders}
2==================================
3
4@brief A description of the C API external decoder interface.
5
6Introduction
7------------
8
9An external custom decoder is one which decodes a CoreSight trace byte stream from a source other
10than an ARM core which cannot be decoded by the standard built-in decoders within the library.
11
12An example of this may be a trace stream from a DSP device.
13
14The external decoder API allows a suitable decoder to be attached to the library and used in the
15same way as the built-in decoders. This means that the external decoder can be created and destroyed
16using the decode tree API, and will integrate seamlessly with any ARM processor decoders that are part
17of the same tree.
18
19An external decoder will be required to use three standard structures:-
20
21- `ocsd_extern_dcd_fact_t` : This is a decoder "factory" that allows the creation of the custom decoders.
22- `ocsd_extern_dcd_inst_t` : This structure provides decoder data to the library for a single decoder instance.
23- `ocsd_extern_dcd_cb_fns` : This structure provides a set of callback functions allowing the decoder to use library functionality in the same way as built-in decoders.
24
25These structures consist of data and function pointers to allow integration with the library infrastructure.
26
27Registering A Decoder
28---------------------
29
30A single API function is provided to allow a decoder to be registered with the library by name.
31
32    ocsd_err_t ocsd_register_custom_decoder(const char *name, ocsd_extern_dcd_fact_t *p_dcd_fact);
33
34This registers the custom decoder with the library using the supplied name and factory structure.
35As part of the registration function the custom decoder will be assigned a protocol ID which may be used in
36API functions requiring this parameter.
37
38Once registered, the standard API functions used with the built-in decoders will work with the custom decoder.
39
40The Factory Structure
41---------------------
42This structure contains the interface that is registered with the library to allow the creation of custom decoder instances.
43
44The mandatory functions that must be provided include:
45- `fnCreateCustomDecoder`  : Creates a decoder. This function will fill in a `ocsd_extern_dcd_inst_t` structure for the decoder instance.
46- `fnDestroyCustomDecoder` : Destroys the decoder. Takes the `decoder_handle` attribute of the instance structure.
47- `fnGetCSIDFromConfig`    : Extracts the CoreSight Trace ID from the decoder configuration structure.
48                             May be called before the create function. The CSID is used as part of the creation process to
49                             attach the decoder to the correct trace byte stream.
50
51`fnPacketToString` : This optional function will provide a human readable string from a protocol specific packet structure.
52
53`protocol_id` : This is filled in when the decoder type is registered with the library. Used in some API
54                calls to specify the decoder protocol type.
55
56
57
58Creating a Custom Decoder Instance
59----------------------------------
60
61Once the custom decoder factory has been registered with the library then using the decoder uses the standard creation API:-
62
63`ocsd_dt_create_decoder(const dcd_tree_handle_t handle, const char *decoder_name, const int create_flags,
64                                             const void *decoder_cfg, unsigned char *pCSID)`
65
66
67This creates a decoder by type name in the current decode tree and attaches it to the trace data stream associated with a CoreSight trace ID extracted from
68the trace configuration.
69
70To create a custom decoder instance simply use the custom name and a pointer to the custom configuration structure.
71
72Calling this on a custom decoder name will result in a call to the factor function `fnCreateCustomDecoder` function:-
73`ocsd_err_t CreateCustomDecoder(const int create_flags, const void *decoder_cfg, const ocsd_extern_dcd_cb_fns *p_lib_callbacks, ocsd_extern_dcd_inst_t *p_decoder_inst)`
74
75This will first require that the `ocsd_extern_dcd_inst_t` structure is populated.
76
77There is are two mandatory function calls in this structure that may be called by the library
78
79   `fnTraceDataIn` : the decoder must provide this as this is called by the library to provide the
80                     raw trace data to the decoder.
81
82    `fn_update_pkt_mon` : Allows the library to communicate when packet sink / packet monitor interfaces are attached to the decoder and in use.
83
84The decoder creation process will also fill in the additional information to allow the library to correctly call back into the custom decoder using the `decoder_handle` parameter.
85
86Secondly the library will provide a structure of callback functions - `ocsd_extern_dcd_cb_fns` - that the decoder can use to access standard library functionality.
87This includes the standard error and message logging functions, the memory access and ARM instruction decode functions, plus the current output sink for generic
88trace elements generated by the decoder. The decoder is not required to use these functions - indeed the ARM instruction decode will not be useful to none ARM
89architecture decoders, but should where possible use these functions if being used as part of a combined ARM / custom decoder tree. This will simplify client
90use of the external decoders.
91
92The `create_flags` parameter will describe the expected operational mode for the decoder. The flags are:-
93- `OCSD_CREATE_FLG_PACKET_PROC`  : Packet processing only - the decoder will split the incoming stream into protocol trace packets and output these.
94- `OCSD_CREATE_FLG_FULL_DECODER` : Full decode - the decoder will split the incoming stream into protocol trace packets and further decode and analyse these to produce generic trace output which may describe the program flow.
95
96Finally the decoder creation function will interpret the custom configuration (`decoder_cfg`) and fill in the CoreSight Trace ID parameter `pCSID`
97for this decoder instance. Decoder configuration structures describe registers and parameters used in programming up the trace source. The only
98minimum requirement is that it is possible to extract a CoreSight trace ID from the configuration to allow the library to attach the correct byte
99stream to the decoder.
100
101
102Example : The echo_test decoder
103--------------------------------
104
105The echo_test decoder is provided to both test the C-API interfaces provided for using custom decoders and as a worked example for using these interfaces.
106
107This decoder is initialised and created by the `c_api_pkt_print_test` program when the `-extern` command line option is used.
108
109In order to use a custom decoder, the header files for that decoder must be included by the client as they are not part of the built-in provided by the standard library includes.
110
111    #include "ext_dcd_echo_test_fact.h"     // provides the ext_echo_get_dcd_fact() fn
112    #include "ext_dcd_echo_test.h"          // provides the echo_dcd_cfg_t config structure.
113
114The `register_extern_decoder()` function in the test shows how simple the API is to use.
115
116The implementation of the decoder provides an external function to get a factory structure.
117
118    p_ext_fact = ext_echo_get_dcd_fact();
119
120Assuming this returns a structure then the decoder is registered by name.
121
122    if (p_ext_fact)
123    {
124        err = ocsd_register_custom_decoder(EXT_DCD_NAME, p_ext_fact);
125    }
126
127After this the test uses the same code path as the built in decoders when testing the custom decoder.
128The test function `ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h)` is called if the test parameters indicate a custom decoder is needed.
129This populates the custom configuration structure specific to the echo_test decoder (`echo_dcd_cfg_t`), then passes this plus the decoder name to the same `create_generic_decoder()` function used when testing the built in decoders.
130
131
132    static ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h)
133    {
134        echo_dcd_cfg_t trace_cfg_ext;
135
136        /* setup the custom configuration */
137        trace_cfg_ext.cs_id = 0x010;
138        if (test_trc_id_override != 0)
139        {
140            trace_cfg_ext.cs_id = (uint32_t)test_trc_id_override;
141        }
142
143        /* create an external decoder - no context needed as we have a single stream to a single handler. */
144        return create_generic_decoder(dcd_tree_h, EXT_DCD_NAME, (void *)&trace_cfg_ext, 0);
145    }
146
147From the test program perspective, these are the only changes made to the test program to test this decoder.
148The `create_generic_decoder()` then uses the normal C-API calls such as `ocsd_dt_create_decoder()` and `ocsd_dt_attach_packet_callback()` to hook the decoder into the decode tree infrastructure.
149