Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 1 | Firmware Configuration Framework |
| 2 | ================================ |
| 3 | |
| 4 | This document provides an overview of the |FCONF| framework. |
| 5 | |
| 6 | Introduction |
| 7 | ~~~~~~~~~~~~ |
| 8 | |
| 9 | The Firmware CONfiguration Framework (|FCONF|) is an abstraction layer for |
| 10 | platform specific data, allowing a "property" to be queried and a value |
| 11 | retrieved without the requesting entity knowing what backing store is being used |
| 12 | to hold the data. |
| 13 | |
| 14 | It is used to bridge new and old ways of providing platform-specific data. |
| 15 | Today, information like the Chain of Trust is held within several, nested |
| 16 | platform-defined tables. In the future, it may be provided as part of a device |
| 17 | blob, along with the rest of the information about images to load. |
| 18 | Introducing this abstraction layer will make migration easier and will preserve |
| 19 | functionality for platforms that cannot / don't want to use device tree. |
| 20 | |
| 21 | Accessing properties |
| 22 | ~~~~~~~~~~~~~~~~~~~~ |
| 23 | |
| 24 | Properties defined in the |FCONF| are grouped around namespaces and |
| 25 | sub-namespaces: a.b.property. |
| 26 | Examples namespace can be: |
| 27 | |
| 28 | - (|TBBR|) Chain of Trust data: tbbr.cot.trusted_boot_fw_cert |
| 29 | - (|TBBR|) dynamic configuration info: tbbr.dyn_config.disable_auth |
| 30 | - Arm io policies: arm.io_policies.bl2_image |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 31 | - GICv3 properties: hw_config.gicv3_config.gicr_base |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 32 | |
| 33 | Properties can be accessed with the ``FCONF_GET_PROPERTY(a,b,property)`` macro. |
| 34 | |
| 35 | Defining properties |
| 36 | ~~~~~~~~~~~~~~~~~~~ |
| 37 | |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 38 | Properties composing the |FCONF| have to be stored in C structures. If |
| 39 | properties originate from a different backend source such as a device tree, |
| 40 | then the platform has to provide a ``populate()`` function which essentially |
| 41 | captures the property and stores them into a corresponding |FCONF| based C |
| 42 | structure. |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 43 | |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 44 | Such a ``populate()`` function is usually platform specific and is associated |
| 45 | with a specific backend source. For example, a populator function which |
| 46 | captures the hardware topology of the platform from the HW_CONFIG device tree. |
| 47 | Hence each ``populate()`` function must be registered with a specific |
| 48 | ``config_type`` identifier. It broadly represents a logical grouping of |
| 49 | configuration properties which is usually a device tree file. |
| 50 | |
| 51 | Example: |
| 52 | - TB_FW: properties related to trusted firmware such as IO policies, |
| 53 | base address of other DTBs, mbedtls heap info etc. |
| 54 | - HW_CONFIG: properties related to hardware configuration of the SoC |
| 55 | such as topology, GIC controller, PSCI hooks, CPU ID etc. |
| 56 | |
| 57 | Hence the ``populate()`` callback must be registered to the (|FCONF|) framework |
| 58 | with the ``FCONF_REGISTER_POPULATOR()`` macro. This ensures that the function |
| 59 | would be called inside the generic ``fconf_populate()`` function during |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 60 | initialization. |
| 61 | |
| 62 | :: |
| 63 | |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 64 | int fconf_populate_topology(uintptr_t config) |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 65 | { |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 66 | /* read hw config dtb and fill soc_topology struct */ |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 67 | } |
| 68 | |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 69 | FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology); |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 70 | |
| 71 | Then, a wrapper has to be provided to match the ``FCONF_GET_PROPERTY()`` macro: |
| 72 | |
| 73 | :: |
| 74 | |
| 75 | /* generic getter */ |
| 76 | #define FCONF_GET_PROPERTY(a,b,property) a##__##b##_getter(property) |
| 77 | |
| 78 | /* my specific getter */ |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 79 | #define hw_config__topology_getter(prop) soc_topology.prop |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 80 | |
| 81 | This second level wrapper can be used to remap the ``FCONF_GET_PROPERTY()`` to |
| 82 | anything appropriate: structure, array, function, etc.. |
| 83 | |
| 84 | Loading the property device tree |
| 85 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 86 | |
| 87 | The ``fconf_load_config()`` must be called to load the device tree containing |
| 88 | the properties' values. This must be done after the io layer is initialized, as |
| 89 | the |DTB| is stored on an external device (FIP). |
| 90 | |
| 91 | .. uml:: ../resources/diagrams/plantuml/fconf_bl1_load_config.puml |
| 92 | |
| 93 | Populating the properties |
| 94 | ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 95 | |
| 96 | Once a valid device tree is available, the ``fconf_populate(config)`` function |
| 97 | can be used to fill the C data structure with the data from the config |DTB|. |
| 98 | This function will call all the ``populate()`` callbacks which have been |
Madhukar Pappireddy | ae9677b | 2020-01-27 13:37:51 -0600 | [diff] [blame] | 99 | registered with ``FCONF_REGISTER_POPULATOR()`` as described above. |
Louis Mayencourt | 8ac387c | 2019-11-08 15:09:15 +0000 | [diff] [blame] | 100 | |
| 101 | .. uml:: ../resources/diagrams/plantuml/fconf_bl2_populate.puml |
Louis Mayencourt | 2979224 | 2020-03-09 16:43:25 +0000 | [diff] [blame] | 102 | |
| 103 | Namespace guidance |
| 104 | ~~~~~~~~~~~~~~~~~~ |
| 105 | |
| 106 | As mentioned above, properties are logically grouped around namespaces and |
| 107 | sub-namespaces. The following concepts should be considered when adding new |
| 108 | properties/namespaces. |
| 109 | The framework differentiates two types of properties: |
| 110 | - Properties used inside common code. |
| 111 | - Properties used inside platform specific code. |
| 112 | |
| 113 | The first category applies to properties being part of the firmware and shared |
| 114 | across multiple platforms. They should be globally accessible and defined |
| 115 | inside the ``lib/fconf`` directory. The namespace must be chosen to reflect the |
| 116 | feature/data abstracted. |
| 117 | Example: |
| 118 | - |TBBR| related properties: tbbr.cot.bl2_id |
| 119 | - Dynamic configuration information: dyn_cfg.dtb_info.hw_config_id |
| 120 | |
| 121 | The second category should represent the majority of the properties defined |
| 122 | within the framework: Platform specific properties. They must be accessed only |
| 123 | within the platform API and are defined only inside the platform scope. The |
| 124 | namespace must contain the platform name under which the properties defined |
| 125 | belong. |
| 126 | Example: |
| 127 | - Arm io framework: arm.io_policies.bl31_id |
| 128 | |