1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     Module definitions.
9  */
10 
11 #ifndef FWK_MODULE_H
12 #define FWK_MODULE_H
13 
14 #include <fwk_element.h>
15 #include <fwk_event.h>
16 #include <fwk_id.h>
17 #include <fwk_io.h>
18 
19 #include <stdbool.h>
20 #include <stdint.h>
21 
22 /*!
23  * \addtogroup GroupLibFramework Framework
24  * \{
25  */
26 
27 /*!
28  * \defgroup GroupModule Modules
29  * \{
30  */
31 
32 /*!
33  * \brief Module types.
34  */
35 enum fwk_module_type {
36     /*! Hardware Abstraction Layer */
37     FWK_MODULE_TYPE_HAL,
38     /*! Device driver */
39     FWK_MODULE_TYPE_DRIVER,
40     /*! Protocol */
41     FWK_MODULE_TYPE_PROTOCOL,
42     /*! Service provider */
43     FWK_MODULE_TYPE_SERVICE,
44     /*! The number of defined module types */
45     FWK_MODULE_TYPE_COUNT
46 };
47 
48 /*!
49  * \brief Module or element state flags.
50  */
51 enum fwk_module_state {
52     /*! The module or element has not yet been initialized */
53     FWK_MODULE_STATE_UNINITIALIZED = 0,
54 
55     /*! The module or element has been initialized successfully */
56     FWK_MODULE_STATE_INITIALIZED,
57 
58     /*! The module or element has bound successfully */
59     FWK_MODULE_STATE_BOUND,
60 
61     /*! The module or element has started successfully */
62     FWK_MODULE_STATE_STARTED,
63 
64     /*! The module or element is suspended */
65     FWK_MODULE_STATE_SUSPENDED,
66 
67     /*! The number of defined module or element states */
68     FWK_MODULE_STATE_COUNT
69 };
70 
71 /*!
72  * \brief Module descriptor.
73  */
74 struct fwk_module {
75     /*! Module type */
76     enum fwk_module_type type;
77 
78     /*! Number of APIs defined by the module */
79     unsigned int api_count;
80 
81     /*! Number of events defined by the module */
82     unsigned int event_count;
83 
84     #ifdef BUILD_HAS_NOTIFICATION
85     /*! Number of notifications defined by the module */
86     unsigned int notification_count;
87     #endif
88 
89     /*!
90      * \brief Stream adapter.
91      *
92      * \details Every module may provide an optional stream adapter, which
93      *      allows it to service input/output requests to and from other modules
94      *      in a fashion similar to standard file operations in the standard
95      *      library.
96      *
97      *      This adapter handles adapter requests to the module, its elements,
98      *      and its sub-elements.
99      */
100     struct fwk_io_adapter adapter;
101 
102     /*!
103      * \brief Pointer to the module initialization function.
104      *
105      * \details This function is invoked during the initialization stage, which
106      *      is the first pre-runtime stage. It is called before any module
107      *      element initialization is performed. This function must not make any
108      *      assumptions about the initialization state of other modules or
109      *      their elements.
110      *
111      * \note This function is \b mandatory and must be implemented by all
112      *      modules.
113      *
114      * \param module_id Identifier of the module being initialized.
115      * \param element_count Number of module elements.
116      * \param data Module-specific configuration data.
117      *
118      * \retval ::FWK_SUCCESS The module was initialized successfully.
119      * \retval ::FWK_E_NOMEM A memory allocation failed.
120      * \return One of the other module-defined error codes.
121      */
122     int (*init)(fwk_id_t module_id, unsigned int element_count,
123                 const void *data);
124 
125     /*!
126      * \brief Pointer to the module element initialization function.
127      *
128      * \details This function is invoked once for each module element during the
129      *      initialization stage. Module element initialization occurs after the
130      *      call to the module initialization function and before the call to
131      *      the module post-initialization function.
132      *
133      *      Elements are initialized in the order they are declared in the
134      *      module configuration data. The initialization function must not
135      *      make any assumptions about the initialization state of other modules
136      *      and their elements.
137      *
138      * \note This function is \b mandatory for modules with elements.
139      *
140      * \param element_id Identifier of the module element being initialized.
141      * \param sub_element_count Number of sub-elements.
142      * \param data Element-specific configuration data.
143      *
144      * \retval ::FWK_SUCCESS The element was initialized successfully.
145      * \retval ::FWK_E_NOMEM A memory allocation failed.
146      * \return One of the other module-defined error codes.
147      */
148     int (*element_init)(fwk_id_t element_id, unsigned int sub_element_count,
149          const void *data);
150 
151     /*!
152      * \brief Pointer to the module post-initialization function.
153      *
154      * \details This function is invoked to finalize the module initialization
155      *      once the module and its elements have been successfully initialized.
156      *
157      *      The framework does not mandate a particular purpose for this
158      *      function. It may be used to deal with dependencies between elements,
159      *      for example.
160      *
161      * \note This function is \b optional.
162      *
163      * \param module_id Identifier of the module element.
164      *
165      * \retval ::FWK_SUCCESS The module post-initialization was successful.
166      * \retval ::FWK_E_NOMEM A memory allocation failed.
167      * \return One of the other module-defined error codes.
168      */
169     int (*post_init)(fwk_id_t module_id);
170 
171     /*!
172      * \brief Pointer to the bind function.
173      *
174      * \details This function provides a place for the module and its elements
175      *      to bind to other modules and/or elements. Bindings expose APIs
176      *      to other modules and elements, and form the core building block of
177      *      cross-module interaction.
178      *
179      *      This function is called by the framework during the bind stage of
180      *      the pre-runtime phase. It is called once over the module and then
181      *      over all its elements in the initial binding, and a second time to
182      *      allow entities with more complex binding strategies to finalize
183      *      their bindings.
184      *
185      *      The first round of calls may be used by a module or element to
186      *      discover the entities it needs to bind to, and the second round to
187      *      bind to them.
188      *
189      * \note This function is \b optional.
190      *
191      * \param id Identifier of the module or element to bind.
192      * \param round Current call round, \c 0 for the first round \c 1 for
193      *      the second round.
194      *
195      * \retval ::FWK_SUCCESS The binding was successful.
196      * \retval ::FWK_E_ACCESS At least one binding request was rejected.
197      * \retval ::FWK_E_NOMEM A memory allocation failed.
198      * \return One of the other module-defined error codes.
199      */
200     int (*bind)(fwk_id_t id, unsigned int round);
201 
202     /*!
203      * \brief Pointer to the start function.
204      *
205      * \details This function is called by the framework for the module and then
206      *      for all of its elements during the start stage. Elements are
207      *      started in the order they are declared in the module configuration
208      *      data.
209      *
210      *      The framework does not mandate a particular purpose for this
211      *      function. It may be used to perform any final processing of the
212      *      module and its elements before entering the runtime phase. A
213      *      possible example of this would be a driver module that must enable
214      *      an interrupt after it has completed initialization.
215      *
216      * \note This function is \b optional.
217      *
218      * \param id Identifier of the module or element to start.
219      *
220      * \retval ::FWK_SUCCESS The module or element was successfully started.
221      * \return One of the other module-defined error codes.
222      */
223     int (*start)(fwk_id_t id);
224 
225     /*!
226      * \brief Pointer to the stop function.
227      *
228      * \details This function is called by the framework for the module and then
229      *      for all of its elements during the stop stage. Elements are
230      *      stopped in the order they are declared in the module configuration
231      *      data.
232      *
233      *      The framework does not mandate a particular purpose for this
234      *      function. It may be used to perform any final processing of the
235      *      module and its elements before entering the suspend phase.
236      *
237      * \note This function is \b optional and aims to release software
238      * resources or to set hardware resources in a proper state before
239      * terminating the SCP software.
240      *
241      * \param id Identifier of the module or element to start.
242      *
243      * \retval ::FWK_SUCCESS The module or element was successfully started.
244      * \return One of the other module-defined error codes.
245      */
246     int (*stop)(fwk_id_t id);
247 
248     /*!
249      * \brief Pointer to the bind request processing function.
250      *
251      * \details This function is called by the framework when it receives a
252      *      request from another entity to bind to the module, or an element of
253      *      the module. It can be called only during the initialization phase
254      *      once 'target_id' has been initialized and during the binding phase.
255      *
256      *      It allows access control, for instance, to deny certain entities
257      *      access. Furthermore, in the case where the module includes different
258      *      implementations of an API, it allows the module to select the
259      *      implementation to provide based on the requesting entity and/or
260      *      target entity.
261      *
262      * \note This function is \b optional.
263      *
264      * \param source_id Identifier of the module or element making the
265      *      bind request.
266      * \param target_id Identifier of the module or element to bind to.
267      * \param api_id Identifier of the API to return.
268      * \param [out] api Pointer to the API implementation to be used by the
269      *      requester.
270      *
271      * \retval ::FWK_SUCCESS The binding request was accepted by the module or
272      *      element.
273      * \retval ::FWK_E_ACCESS The binding request was rejected by the module or
274      *      element.
275      * \return One of the other module-defined error codes.
276      */
277     int (*process_bind_request)(fwk_id_t source_id, fwk_id_t target_id,
278                                 fwk_id_t api_id, const void **api);
279 
280     /*!
281      * \brief Process an event.
282      *
283      * \details This function is called by the framework for events targeting
284      *      the module or one of its elements.
285      *
286      * \note This function is \b optional. If a response event is expected and
287      *      the ::fwk_event::is_delayed_response flag is not set by the
288      *      processing function then the response event is immediately and
289      *      automatically sent to the event's source by the framework. If
290      *      however the ::fwk_event::is_delayed_response flag is set by the
291      *      processing function then the framework does not send the response
292      *      event and it is the responsability of the event's target to send it
293      *      at some point.
294      *
295      * \param event Pointer to the event to be processed.
296      * \param [out] resp_event The response event to the provided event if
297      *      any.
298      *
299      * \retval ::FWK_SUCCESS The event was processed successfully.
300      * \return One of the other module-defined error codes.
301      */
302     int (*process_event)(const struct fwk_event *event,
303                          struct fwk_event *resp_event);
304 
305     /*!
306      * \brief Process a notification.
307      *
308      * \details This function is called by the framework when a notification is
309      *      received by a module, element, or sub-element.
310      *
311      * \note This function is \b optional.
312      *
313      * \param event Pointer to the notification event to be processed.
314      * \param [out] resp_event The response event to the provided event, if
315      *      any.
316      *
317      * \retval ::FWK_SUCCESS The notification was processed successfully.
318      * \return One of the other module-defined error codes.
319      */
320     int (*process_notification)(const struct fwk_event *event,
321                                 struct fwk_event *resp_event);
322 
323 };
324 
325 /*!
326  * \brief Define a static element table with the content of the table.
327  *
328  * \param[in] ... An array of elements in the form `{ X, Y, Z, { 0 } }`.
329  *
330  * \see ::fwk_module_elements::table
331  */
332 #define FWK_MODULE_STATIC_ELEMENTS(...) \
333     { \
334         .type = FWK_MODULE_ELEMENTS_TYPE_STATIC, \
335         .table = (const struct fwk_element[])__VA_ARGS__, \
336     }
337 
338 /*!
339  * \brief Define a static element table with a pointer to the table.
340  *
341  * \details Some element tables require extra preprocessing beforehand. As it is
342  *      undefined behaviour for preprocessing macros to occur within macro
343  *      argument lists, this macro has been provided to work around this
344  *      language restriction.
345  *
346  * \param[in] TABLE Pointer to the static element table.
347  *
348  * \see ::fwk_module_elements::table
349  */
350 #define FWK_MODULE_STATIC_ELEMENTS_PTR(TABLE) \
351     { \
352         .type = FWK_MODULE_ELEMENTS_TYPE_STATIC, \
353         .table = TABLE, \
354     }
355 
356 /*!
357  * \brief Define a dynamic element table.
358  *
359  * \details Element table generators are functions that take a module identifier
360  *      and return an element table. They will be called once the module has
361  *      begun initialization, and may allocate a variable number of elements.
362  *
363  * \param[in] GENERATOR Function to generate the element table.
364  *
365  * \see ::fwk_module_elements::generator
366  */
367 #define FWK_MODULE_DYNAMIC_ELEMENTS(GENERATOR) \
368     { \
369         .type = FWK_MODULE_ELEMENTS_TYPE_DYNAMIC, \
370         .generator = (GENERATOR), \
371     }
372 
373 /*!
374  * \brief Element table type.
375  */
376 enum fwk_module_elements_type {
377     FWK_MODULE_ELEMENTS_TYPE_NONE, /*!< No element table. */
378     FWK_MODULE_ELEMENTS_TYPE_STATIC, /*<! Static element table. */
379     FWK_MODULE_ELEMENTS_TYPE_DYNAMIC, /*<! Dynamic element table. */
380 };
381 
382 /*!
383  * \brief Element table.
384  */
385 struct fwk_module_elements {
386     /*!
387      * \brief Element table type.
388      *
389      * \details Elements may be statically defined, or they can be generated
390      *      once the module comes online.
391      */
392     enum fwk_module_elements_type type;
393 
394     /*!
395      * \brief Element table data.
396      */
397     union {
398         /*!
399          * \brief Pointer to the function to get the table of element
400          *      descriptions.
401          *
402          * \param[in] module_id Identifier of the module.
403          *
404          * \details The table of module element descriptions ends with an
405          *      invalid element description where the pointer to the element
406          *      name is equal to `NULL`.
407          *
408          * \warning The framework does not copy the element description data
409          *      and keep a pointer to the ones returned by this function.
410          *      Pointers returned by this function must thus points to data
411          *      with static storage or data stored in memory allocated from
412          *      the memory management component.
413          *
414          * \return Pointer to table of element descriptions.
415          */
416         const struct fwk_element *(*generator)(fwk_id_t module_id);
417 
418         /*!
419          * \brief Table of element descriptions.
420          *
421          * \details The table of module element descriptions ends with an
422          *      invalid element description where the pointer to the element
423          *      name is equal to `NULL`.
424          */
425         const struct fwk_element *table;
426     };
427 };
428 
429 /*!
430  * \brief Module configuration.
431  */
432 struct fwk_module_config {
433     /*! Pointer to the module-specific configuration data */
434     const void *data;
435 
436     /*! Element table */
437     struct fwk_module_elements elements;
438 };
439 
440 /*!
441  * \brief Check if an identifier refers to a valid module.
442  *
443  * \param id Identifier to be checked.
444  *
445  * \retval true The identifier refers to a valid module.
446  * \retval false The identifier does not refer to a valid module.
447  */
448 bool fwk_module_is_valid_module_id(fwk_id_t id);
449 
450 /*!
451  * \brief Check if an identifier refers to a valid element.
452  *
453  * \param id Identifier to be checked.
454  *
455  * \retval true The identifier refers to a valid element.
456  * \retval false The identifier does not refer to a valid element.
457  */
458 bool fwk_module_is_valid_element_id(fwk_id_t id);
459 
460 /*!
461  * \brief Check if an identifier refers to a valid sub-element.
462  *
463  * \param id Identifier to be checked.
464  *
465  * \retval true The identifier refers to a valid sub-element.
466  * \retval false The identifier does not refer to a valid sub-element.
467  */
468 bool fwk_module_is_valid_sub_element_id(fwk_id_t id);
469 
470 /*!
471  * \brief Check if an identifier refers to a valid module, element or
472  *      sub-element.
473  *
474  * \param id Identifier to be checked.
475  *
476  * \retval true The identifier refers to a valid module, element or
477  *      sub-element.
478  * \retval false The identifier does not refer to a valid module, element or
479  *      sub-element.
480  */
481 bool fwk_module_is_valid_entity_id(fwk_id_t id);
482 
483 /*!
484  * \brief Check if an identifier refers to a valid API.
485  *
486  * \param id Identifier to be checked.
487  *
488  * \retval true The identifier refers to a valid API.
489  * \retval false The identifier does not refer to a valid API.
490  */
491 bool fwk_module_is_valid_api_id(fwk_id_t id);
492 
493 /*!
494  * \brief Check if an identifier refers to a valid event.
495  *
496  * \param id Identifier to be checked.
497  *
498  * \retval true The identifier refers to a valid event.
499  * \retval false The identifier does not refer to a valid event.
500  */
501 bool fwk_module_is_valid_event_id(fwk_id_t id);
502 
503 /*!
504  * \brief Check if an identifier refers to a valid notification.
505  *
506  * \param id Identifier to be checked.
507  *
508  * \retval true The identifier refers to a valid notification.
509  * \retval false The identifier does not refer to a valid notification.
510  */
511 bool fwk_module_is_valid_notification_id(fwk_id_t id);
512 
513 /*!
514  * \brief Get the number of elements within a module.
515  *
516  * \param module_id Identifier of the module.
517  *
518  * \retval ::FWK_E_PARAM The identifier of the module is invalid.
519  * \return Number of module elements.
520  */
521 int fwk_module_get_element_count(fwk_id_t module_id);
522 
523 /*!
524  * \brief Get the number of sub-elements within an element.
525  *
526  * \param element_id Identifier of the element.
527  *
528  * \retval ::FWK_E_PARAM The identifier of the element is invalid.
529  * \return Number of sub-elements.
530  */
531 int fwk_module_get_sub_element_count(fwk_id_t element_id);
532 
533 /*!
534  * \brief Get the name of a element.
535  *
536  * \param id Identifier of the  element.
537  *
538  * \return The pointer to the element name, NULL if the identifier is
539  *      not valid.
540  */
541 const char *fwk_module_get_element_name(fwk_id_t id);
542 
543 /*!
544  * \brief Get the configuration data of a module or element.
545  *
546  * \param id Identifier of the module or element.
547  *
548  * \return The pointer to the module/element-specific configuration data, NULL
549  *      if the identifier is not valid.
550  */
551 const void *fwk_module_get_data(fwk_id_t id);
552 
553 /*!
554  * \brief Bind to an API of a module or an element.
555  *
556  * \details The framework will accept the bind request in one of the two
557  *      following cases:
558  *      1) The execution is at the pre-runtime initialization stage and the
559  *         entity 'target_id' has already been initialized.
560  *      2) The execution is at the pre-runtime binding stage.
561  *
562  * \param target_id Identifier of the module or element to bind to.
563  * \param api_id Identifier of the API to return an implementation of.
564  * \param api [out] Pointer to storage for the pointer to the API.
565  *
566  * \retval ::FWK_SUCCESS The API was returned.
567  * \retval ::FWK_E_PARAM A least one of the identifiers is invalid.
568  * \retval ::FWK_E_STATE Call outside of the pre-runtime bind stage.
569  * \retval ::FWK_E_ACCESS The access to the API was refused.
570  * \retval ::FWK_E_HANDLER The returned API pointer is invalid (NULL).
571  */
572 int fwk_module_bind(fwk_id_t target_id, fwk_id_t api_id, const void *api);
573 
574 /*!
575  * \brief Get the [stream adapter](::fwk_module::adapter) of a module.
576  *
577  * \details Stream adapters are owned by the module, rather than its elements or
578  *      sub-elements, but element and sub-element identifiers may also be
579  *      provided to this function to get the adapter of the parent module.
580  *
581  * \param[out] adapter Pointer to the stream adapter belonging to the entity, or
582  *      a null pointer value if the module has no registered adapter.
583  * \param[in] id Identifier of an entity.
584  *
585  * \return Status code representing the result of the operation.
586  *
587  * \retval ::FWK_SUCCESS The operation succeeded.
588  * \retval ::FWK_E_PARAM An invalid parameter was encountered:
589  *      - The `adapter` parameter was a null pointer value.
590  *      - The `id` parameter did not resolve to a valid entity.
591  */
592 int fwk_module_adapter(const struct fwk_io_adapter **adapter, fwk_id_t id);
593 
594 /*!
595  * \internal
596  *
597  * \brief Initialize the module component.
598  *
599  * \details Initializes the module framework component contexts, allowing
600  *      module details to be accessed through the module interfaces. This does
601  *      not start any modules.
602  */
603 void fwk_module_init(void);
604 
605 /*!
606  * \}
607  */
608 
609 /*!
610  * \}
611  */
612 
613 #endif /* FWK_MODULE_H */
614