5. Firmware Configuration Framework

This document provides an overview of the FCONF framework.

5.1. Introduction

The Firmware CONfiguration Framework (FCONF) is an abstraction layer for platform specific data, allowing a “property” to be queried and a value retrieved without the requesting entity knowing what backing store is being used to hold the data.

It is used to bridge new and old ways of providing platform-specific data. Today, information like the Chain of Trust is held within several, nested platform-defined tables. In the future, it may be provided as part of a device blob, along with the rest of the information about images to load. Introducing this abstraction layer will make migration easier and will preserve functionality for platforms that cannot / don’t want to use device tree.

5.2. Accessing properties

Properties defined in the FCONF are grouped around namespaces and sub-namespaces: a.b.property. Examples namespace can be:

  • (TBBR) Chain of Trust data: tbbr.cot.trusted_boot_fw_cert

  • (TBBR) dynamic configuration info: tbbr.dyn_config.disable_auth

  • Arm io policies: arm.io_policies.bl2_image

Properties can be accessed with the FCONF_GET_PROPERTY(a,b,property) macro.

5.3. Defining properties

Properties composing the FCONF have to be stored in C structures. If another backing store is wanted to be used, the platform has to provide a populate() function to fill the corresponding C structure.

The populate() function must be registered to the FCONF framework with the FCONF_REGISTER_POPULATOR() macro. This ensures that the function would be called inside the generic fconf_populate() function during initialization.

int fconf_populate_tbbr_dyn_config(uintptr_t config)
{
    /* read dtb and fill tbbr_dyn_config struct */
}

FCONF_REGISTER_POPULATOR(fconf_populate_tbbr_dyn_config);

Then, a wrapper has to be provided to match the FCONF_GET_PROPERTY() macro:

/* generic getter */
#define FCONF_GET_PROPERTY(a,b,property)    a##__##b##_getter(property)

/* my specific getter */
#define tbbr__dyn_config_getter(id) tbbr_dyn_config.id

This second level wrapper can be used to remap the FCONF_GET_PROPERTY() to anything appropriate: structure, array, function, etc..

5.4. Loading the property device tree

The fconf_load_config() must be called to load the device tree containing the properties’ values. This must be done after the io layer is initialized, as the DTB is stored on an external device (FIP).

@startuml

box "BL1 common code"
	participant bl1_main
	participant bl_common
end box

box "arm platform code" #LightBlue
	participant fvp_bl1_setup
	participant arm_bl1_setup
	participant arm_io_storage
end box

box "platform common code"
	participant plat_bl1_common
	participant fconf
end box

bl1_main -> fvp_bl1_setup : bl1_platform_setup()
fvp_bl1_setup -> arm_bl1_setup : arm_bl1_platform_setup()
arm_bl1_setup -> arm_io_storage : plat_arm_io_setup()
note over arm_io_storage : register and setup fip
arm_bl1_setup -> fconf : fconf_load_config()
activate fconf
	note over fconf
		create and populate an
		image_desc_t for TB_FW_CONFIG
	end note
	fconf -> bl_common : load_auth_image(TB_FW_CONFIG_ID, &image_info)
	activate bl_common
	note over bl_common
		load and auth image from fip
		with info from plat_io_policy
	end note
	bl_common -> arm_io_storage
	arm_io_storage -> fconf: FCONF_GET_PROPERTY(arm, arm_io_policies, tb_fw_cfg)
	note over fconf: use staticaly defined policies in bl1
	fconf <- bl_common : image_info
	deactivate bl_common
	note over fconf : get tb_fw_config_dtb from image_info
	fconf -> plat_bl1_common : bl1_plat_get_image_desc(BL2_IMAGE_ID)
	fconf <- plat_bl1_common : BL2_IMAGE_DESC
	note over fconf
		set ep_info.args.arg0 of BL2_IMAGE_DESC
		to TB_FW_CONFIG base address
	end note
arm_bl1_setup <- fconf
deactivate fconf

== load & auth, prepare and jump to BL2 ==

@enduml

5.5. Populating the properties

Once a valid device tree is available, the fconf_populate(config) function can be used to fill the C data structure with the data from the config DTB. This function will call all the populate() callbacks which have been registered with FCONF_REGISTER_POPULATOR().

@startuml

box "BL2 common code"
	participant bl2_entrypoint
	participant bl2_main
end box

box "platform common code"
	participant fconf
	participant fconf_tbbr_getter
end box

box "arm platform code" #LightBlue
	participant arm_bl2_setup
	participant arm_io_storage
	participant arm_fconf_io
end box

== bl2 setup ==
bl2_entrypoint -> bl2_main : bl2_setup()
bl2_main -> arm_bl2_setup : bl2_early_platform_setup2(\n\t arg0, arg1, arg2, arg3)
note over arm_bl2_setup
	arg0 = tb_fw_config
	arg1 = mem_layout
end note
arm_bl2_setup -> arm_bl2_setup : arm_bl2_early_platform_setup(\n\t tb_fw_config, mem_layout)
activate arm_bl2_setup
	arm_bl2_setup -> fconf: fconf_polulate(tb_fw_config)
	activate fconf
		fconf -> fconf_tbbr_getter: fconf_populate_tbbr_dyn_config(uintptr_t dtb)
		note over fconf_tbbr_getter: read tbbr propeties from dtb
		fconf -> arm_fconf_io: fconf_populate_arm_io_policies(uintptr_t dtb)
		note over arm_fconf_io: read arm io propeties from dtb
	deactivate fconf
	arm_bl2_setup -> arm_io_storage : plat_arm_io_setup()
	note over arm_io_storage: use populated properties
deactivate arm_bl2_setup

== bl2 main ==

@enduml