[U-Boot] [RFC PATCH 04/11] SPL: FIT: allow loading multiple images

André Przywara andre.przywara at arm.com
Tue Jan 24 00:52:42 CET 2017


On 23/01/17 02:49, Kever Yang wrote:
> Hi Andre,
> 
> On 01/22/2017 06:58 PM, André Przywara wrote:
>> On 22/01/17 07:08, Kever Yang wrote:
>>> Hi Andre,
>>>
>>>      Thanks for your patches, this is great help for enable ATF on
>>> U-Boot
>>> SPL.
>>> For ATF use case, we would like to identify which one is bl31 for we
>>> need to
>>> get entry point for it while we only need load address for other image.
>>> Any idea on get this information from different "loadables"?
>> So I thought this use case is covered by the current scheme?
>>
>> See below ...
>>
>>> On 01/20/2017 09:53 AM, Andre Przywara wrote:
>>>> So far we were not using the FIT image format to its full potential:
>>>> The SPL FIT loader was just loading the first image from the /images
>>>> node plus one of the listed DTBs.
>>>> Now with the refactored loader code it's easy to load an arbitrary
>>>> number of images in addition to the two mentioned above.
>>>> As described in the FIT image source file format description, iterate
>>>> over all images listed at the "loadables" property in the configuration
>>>> node and load every image at its desired location.
>>>> This allows to load any kind of images:
>>>> - firmware images to execute before U-Boot proper (for instance
>>>>     ARM Trusted Firmware (ATF))
>>>> - firmware images for management processors (SCP, arisc, ...)
>>>> - firmware images for devices like WiFi controllers
>>>> - bit files for FPGAs
>>>> - additional configuration data
>>>> - kernels and/or ramdisks
>>>> The actual usage of this feature would be platform and/or board
>>>> specific.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara at arm.com>
>>>> ---
>>>>    common/spl/spl_fit.c | 27 +++++++++++++++++++++++++++
>>>>    1 file changed, 27 insertions(+)
>>>>
>>>> diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
>>>> index d4149c5..18269f7 100644
>>>> --- a/common/spl/spl_fit.c
>>>> +++ b/common/spl/spl_fit.c
>>>> @@ -190,6 +190,7 @@ int spl_load_simple_fit(struct spl_image_info
>>>> *spl_image,
>>>>        struct spl_image_info image_info;
>>>>        int node, images;
>>>>        int base_offset, align_len = ARCH_DMA_MINALIGN - 1;
>>>> +    int index = 0;
>>>>          /*
>>>>         * Figure out where the external images start. This is the base
>>>> for the
>>>> @@ -234,6 +235,11 @@ int spl_load_simple_fit(struct spl_image_info
>>>> *spl_image,
>>>>        if (node < 0) {
>>>>            debug("could not find firmware image, trying
>>>> loadables...\n");
>>>>            node = spl_fit_get_image_node(fit, images, "loadables", 0);
>>>> +        /*
>>>> +         * If we pick the U-Boot image from "loadables", start at
>>>> +         * the second image when later loading additional images.
>>>> +         */
>>>> +        index = 1;
>>>>        }
>>>>        if (node < 0) {
>>>>            debug("%s: Cannot find u-boot image node: %d\n",
>>>> @@ -259,5 +265,26 @@ int spl_load_simple_fit(struct spl_image_info
>>>> *spl_image,
>>>>        image_info.load_addr = spl_image->load_addr + spl_image->size;
>>>>        spl_load_fit_image(info, sector, fit, base_offset, node,
>>>> &image_info);
>>>>    +    /* Now check if there are more images for us to load */
>>>> +    for (; ; index++) {
>>>> +        node = spl_fit_get_image_node(fit, images, "loadables",
>>>> index);
>>>> +        if (node < 0)
>>>> +            break;
>>>> +
>>>> +        spl_load_fit_image(info, sector, fit, base_offset, node,
>>>> +                   &image_info);
>>>> +
>>>> +        /*
>>>> +         * If the "firmware" image did not provide an entry point,
>>>> +         * use the first valid entry point from the loadables.
>>>> +         */
>>>> +        if (spl_image->entry_point == -1U &&
>>>> +            image_info.entry_point != -1U)
>>>> +            spl_image->entry_point = image_info.entry_point;
>> So this part here saves the entry point from the first image which
>> provides an "entry" property in the loadables section, given that
>> "firmware" didn't provide (a legal) one.
>>
>> So depending on what you want, these are the options:
>> a) You want to branch to U-Boot (default case if mkimage -f auto is
>> used): You either don't specify an explicit entry point at all or
>> provide an "entry" property for the U-Boot "firmware" image.
>> The code below at the end of this function takes care of this.
>> b) You want to branch to something else (bl31.bin): You make sure there
>> is no explicit entry point in "firmware", instead put one "entry"
>> property in the bl31 image description you want to boot. This will then
>> branch to that instead of U-Boot.
>> Check the example .its in patch 10/11 for an example of this.
>>
>> So does this fit for you? Or is there a problem with this?
> 
> So that means only one 'entry' can be present even if there are more
> than one image, right?

Well, there can be more nodes with entry properties, but the code just
takes the first one and ignores the others. Because logically there is
only one entry point after the SPL.

> I think every "firmware" image is possible to have both "load" and
> "entry" node,
> for example if we have bl31, bl32 and bl33(U-Boot) in one FIT image,
> then we need to fill the bl31_params_t structure with bl32 entry point
> and U-Boot entry point,
> so that bl31 able to call bl32 and bl33.

Well, yes, but this is very ATF (or platform) specific. This series aims
to use a generic solution, which does not need to be adapted to every
platform. At the end of the day U-Boot can only jump once into an image.

I guess we could implement something which waits for a return: "bx"
instead of "b", upon return try the next images. If it doesn't return:
fair enough, it probably just went ahead with booting on its own. But I
am not sure this is overly useful, since any kind of firmware would
probably want to setup the system and thus would destroy U-Boot's setup
(page tables, stack pointer, etc.) And I think it wouldn't help in your
case.

I think what we should do instead is allowing platform specific
additions to the loader code. For instance I saw that x86 introduced a
"setup" property to hook in some pre-boot code. This is used by U-Boot
proper, not SPL, but we could piggy-back on this idea. Maybe a "setup"
property in a configuration node points to some special image node,
which contains platform specific properties. Each platform is then
expected to provide a specialised node parser, which can then deal with
this setup node. Along the lines of:

images {
	atf-setup at 1 {
		data = /incbin/("../../bl31.bin");
		atf-bl32 = "bl32 at 1";
		atf-bl33 = "uboot at 1";
		atf-bl31-params-offset = <0x124>;
		load = < ... >;
		entry = < ... >;
	};
	bl32 at 1 {
		data = /incbin/("../../bl32.bin");
		load = <...>;
	};
	uboot at 1 {
		data = /incbin/("../../u-boot-nodtb.bin");
		load = <...>;
	};
...
};
configurations {
	config at 1 {
		description = "rk3399-evb";
		firmware = "uboot at 1";
		setup = "atf-setup at 1";
		loadables = "bl32 at 1";
		fdt = "fdt at 1";
	};
};

Then have some RK specific parser code that follows the "setup" property
(in this case to "atf-setup at 1") and reads the special properties in
there to do its magic: read the load addresses of the referenced images
and setup the structure, its address being in "atf-bl31-params-offset".

This way you could control everything from the FIT image nodes. Ideally
this would be even RK agnostic, instead providing a generic ATF solution.

Another possibility would be to have some small shim that gets loaded
instead of bl31.bin and which fills up the bl31_params_t structure.
Though I guess it would be hard to communicate the parameters.

Or can't you simply hard code the bl32 and bl33 load addresses into
bl31? I can imagine you end up with them being loaded on certain
addresses (SRAM) only anyway. On Allwinner for instance the U-Boot load
address is hardcoded in bl31.bin, so we don't need to take care of this.

> That's why I think we need to identify each of the "firmware", but not
> only know they are "loadables".

I don't know if people like the idea of introducing a lot of special
properties into a configuration node, that's why the idea of confining
everything into a platform-specific node. Maybe we even use compatible=
strings?

Cheers,
Andre.

>>>> +    }
>>>> +
>>>> +    if (spl_image->entry_point == -1U || spl_image->entry_point == 0)
>>>> +        spl_image->entry_point = spl_image->load_addr;
>> This statement here takes the load address of the "firmware" image as an
>> entry point if none is provided explicitly.
>>
>> Cheers,
>> Andre.
>>
>>>> +
>>>>        return 0;
>>>>    }
>>
>>
>>
>>
>>
> 
> 



More information about the U-Boot mailing list