diff mbox series

[U-Boot,v2,1/8] image: android: Add functions for handling dtb field

Message ID 20191023143427.10865-2-semen.protsenko@linaro.org
State Changes Requested
Delegated to: Tom Rini
Headers show
Series am57xx: Implement Android 10 boot flow | expand

Commit Message

Sam Protsenko Oct. 23, 2019, 2:34 p.m. UTC
Android Boot Image v2 adds "DTB" payload (and corresponding field in the
image header). Provide functions for its handling:

  - android_image_get_dtb_by_index(): Obtain DTB file from "DTB" part of
    boot image, by file index
  - android_image_print_dtb_contents(): Iterate over all DTB files in
    "DTB" part of boot image and print those files info

"DTB" payload might be in one of the following formats:
  1. concatenated DTB files
  2. Android DTBO format

The latter requires "android-image-dt.c" functionality, so this commit
selects that file for building for CONFIG_ANDROID_BOOT_IMAGE option.

Right now this new functionality isn't used, but it can be used further.
As it's required to apply some specific dtbo file(s) from "dtbo"
partition, we can't automate this process inside of "bootm" command. But
we can do next:
  - come up with some new command like "bootimg" to extract dtb file
    from boot image (using functions from this patch)
  - extract desired dtbo files from "dtbo" partition using "dtimg"
    command
  - merge dtbo files into dtb file using "fdt apply" command
  - pass resulting dtb file into bootm command in order to boot the
    Android kernel with Android ramdisk from boot image

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
---
Changes in v2:
  - provide mem mappings for sandbox
  - rebase on top of master

 common/Makefile        |   2 +-
 common/image-android.c | 215 +++++++++++++++++++++++++++++++++++++++++
 include/image.h        |   5 +
 3 files changed, 221 insertions(+), 1 deletion(-)

Comments

Eugeniu Rosca Oct. 29, 2019, 1:49 a.m. UTC | #1
Hi Sam,

On Wed, Oct 23, 2019 at 05:34:20PM +0300, Sam Protsenko wrote:
> Android Boot Image v2 adds "DTB" payload (and corresponding field in the
> image header). Provide functions for its handling:

I believe this totally new degree of freedom brought by "Android Boot
Image v2" might unintentionally make some users more unhappy [0], since
it enables yet another way of passing a DTB to the Android kernel.

It looks to me that there are at least three valid design choices for
DTB storage/passing which platform maintainers have to consider:
 A. Android Image second area [1-2]
 B. Dedicated DTB/DTBO partitions on a block device
 C. DTB area in Android Image v2

While there are some major disadvantages for [A][1-2], [B] and [C] look
more or less equivalent and will most likely only differ in the tooling
used to generate and extract the useful/relevant artifacts.

Not to mention that hybrids [B+C] are also possible.
Which solution should we pick as a long-term one?

[0] https://en.wikipedia.org/wiki/The_Paradox_of_Choice
[1] 104816142f9c6a ("parse the second area of android image")
[2] 6a7b406aa8b981 ("fdt: support booting with dtb in Android image")

[..]

>  common/Makefile        |   2 +-
>  common/image-android.c | 215 +++++++++++++++++++++++++++++++++++++++++
>  include/image.h        |   5 +
>  3 files changed, 221 insertions(+), 1 deletion(-)
> 
> diff --git a/common/Makefile b/common/Makefile
> index 302d8beaf3..7e5f5058b3 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -108,7 +108,7 @@ endif
>  
>  obj-y += image.o
>  obj-$(CONFIG_ANDROID_AB) += android_ab.o
> -obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
> +obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o

I expect that in a not so distant future, Android users who care
about performance aspects of their system (e.g. in automotive sector,
where boot time is paramount to achieve ~2s to Rear View Camera) will
attempt optimizing U-Boot by compiling out features they don't need.

With this background:
 - Would it make sense to allow users to selectively enable and disable
   support for A/B-capable and non-A/B devices? My guess is that it
   is currently not an important development/review criteria, since
   particularly image-android-dt.c implements functions, some of which
   are A/B-specific, some non-A/B-specific (e.g. android_image_get_dtbo)
   and some are common.
 - I would try to avoid wiring the same compilation unit to Kbuild
   (e.g. image-android-dt.o) via multiple Kconfig symbols
   (CONFIG_ANDROID_BOOT_IMAGE and CONFIG_CMD_DTIMG) since this makes
   the relationship between the CONFIG symbols unclear. As a user, I
   would like to see a simple mapping between compiled objects and
   Kconfig symbols, eventually reflecting a hierarchy/dependency:

   config ANDROID_BOOT_IMAGE
      select ANDROID_BOOT_IMAGE_DT

   config DTIMG
      select ANDROID_BOOT_IMAGE_DT

[..]

> diff --git a/common/image-android.c b/common/image-android.c
> index 3564a64221..5e721a27a7 100644
> --- a/common/image-android.c
> +++ b/common/image-android.c
> @@ -6,10 +6,12 @@
>  #include <common.h>
>  #include <env.h>
>  #include <image.h>
> +#include <image-android-dt.h>
>  #include <android_image.h>
>  #include <malloc.h>
>  #include <errno.h>
>  #include <asm/unaligned.h>
> +#include <mapmem.h>
>  
>  #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR	0x10008000
>  
> @@ -195,6 +197,122 @@ int android_image_get_second(const struct andr_img_hdr *hdr,
>  	return 0;
>  }
>  
> +/**
> + * android_image_get_dtb_img_addr() - Get the address of DTB area in boot image.
> + * @hdr_addr: Boot image header address
> + * @addr: Will contain the address of DTB area in boot image
> + *
> + * Return: true on success or false on fail.
> + */
> +static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr)
> +{
> +	const struct andr_img_hdr *hdr;
> +	ulong dtb_img_addr;
> +	bool res = true;
> +
> +	hdr = map_sysmem(hdr_addr, sizeof(*hdr));
> +	if (android_image_check_header(hdr)) {
> +		printf("Error: Boot Image header is incorrect\n");
> +		res = false;
> +		goto exit;
> +	}
> +
> +	if (hdr->header_version < 2) {
> +		printf("Error: header_version must be >= 2 to get dtb\n");
> +		res = false;
> +		goto exit;
> +	}
> +
> +	if (hdr->dtb_size == 0) {
> +		printf("Error: dtb_size is 0\n");
> +		res = false;
> +		goto exit;
> +	}
> +
> +	/* Calculate the address of DTB area in boot image */
> +	dtb_img_addr = hdr_addr;
> +	dtb_img_addr += hdr->page_size;
> +	dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
> +	dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
> +	dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size);
> +	dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
> +
> +	if (addr)
> +		*addr = dtb_img_addr;

In this recent series, I noticed a consistent preference towards
doing a lot of processing with returning nothing to the caller in
case of an invalid argument. Is this by choice?
Sam Protsenko Dec. 2, 2019, 5:19 p.m. UTC | #2
Hi Eugeniu,

On Tue, Oct 29, 2019 at 3:49 AM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
>
> Hi Sam,
>
> On Wed, Oct 23, 2019 at 05:34:20PM +0300, Sam Protsenko wrote:
> > Android Boot Image v2 adds "DTB" payload (and corresponding field in the
> > image header). Provide functions for its handling:
>
> I believe this totally new degree of freedom brought by "Android Boot
> Image v2" might unintentionally make some users more unhappy [0], since
> it enables yet another way of passing a DTB to the Android kernel.
>
> It looks to me that there are at least three valid design choices for
> DTB storage/passing which platform maintainers have to consider:
>  A. Android Image second area [1-2]
>  B. Dedicated DTB/DTBO partitions on a block device
>  C. DTB area in Android Image v2
>
> While there are some major disadvantages for [A][1-2], [B] and [C] look
> more or less equivalent and will most likely only differ in the tooling
> used to generate and extract the useful/relevant artifacts.
>
> Not to mention that hybrids [B+C] are also possible.
> Which solution should we pick as a long-term one?
>

My opinion is next: we should provide means (commands) to achieve any
of [A,B,C] options. Then user (I mean, U-Boot developer who implements
boot for each particular board) should decide which approach to use.
Also [D] FIT image can be used instead of Android Boot Image. But we
should remember that Google requires *mandatory* for all *new* devices
(starting with Android 10) to stick with [C] approach only. Option [B]
might be harder to handle from AVB verification point of view. Btw,
when we come to "boot_android" command, I think we'll need to
implement only officially recommended boot method. Maybe provide a
param to choose whether to do Android-9 or Android-10 boot scheme.

Anyway, the short answer is: we should provide a bunch of isolated
commands to allow the user to implement any boot method.

Also, this particular patch doesn't change boot behavior (it only adds
functions to handle dtb field), so it should be backward-compatible.

> [0] https://en.wikipedia.org/wiki/The_Paradox_of_Choice
> [1] 104816142f9c6a ("parse the second area of android image")
> [2] 6a7b406aa8b981 ("fdt: support booting with dtb in Android image")
>
> [..]
>
> >  common/Makefile        |   2 +-
> >  common/image-android.c | 215 +++++++++++++++++++++++++++++++++++++++++
> >  include/image.h        |   5 +
> >  3 files changed, 221 insertions(+), 1 deletion(-)
> >
> > diff --git a/common/Makefile b/common/Makefile
> > index 302d8beaf3..7e5f5058b3 100644
> > --- a/common/Makefile
> > +++ b/common/Makefile
> > @@ -108,7 +108,7 @@ endif
> >
> >  obj-y += image.o
> >  obj-$(CONFIG_ANDROID_AB) += android_ab.o
> > -obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
> > +obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
>
> I expect that in a not so distant future, Android users who care
> about performance aspects of their system (e.g. in automotive sector,
> where boot time is paramount to achieve ~2s to Rear View Camera) will
> attempt optimizing U-Boot by compiling out features they don't need.
>
> With this background:
>  - Would it make sense to allow users to selectively enable and disable
>    support for A/B-capable and non-A/B devices? My guess is that it
>    is currently not an important development/review criteria, since
>    particularly image-android-dt.c implements functions, some of which
>    are A/B-specific, some non-A/B-specific (e.g. android_image_get_dtbo)
>    and some are common.
>  - I would try to avoid wiring the same compilation unit to Kbuild
>    (e.g. image-android-dt.o) via multiple Kconfig symbols
>    (CONFIG_ANDROID_BOOT_IMAGE and CONFIG_CMD_DTIMG) since this makes
>    the relationship between the CONFIG symbols unclear. As a user, I
>    would like to see a simple mapping between compiled objects and
>    Kconfig symbols, eventually reflecting a hierarchy/dependency:
>
>    config ANDROID_BOOT_IMAGE
>       select ANDROID_BOOT_IMAGE_DT
>
>    config DTIMG
>       select ANDROID_BOOT_IMAGE_DT
>

I thought about that 4 months ago when implementing this patch, even
experimented with that. But decided to just add image-android-dt.o in
Makefile instead, don't remember for what reason exactly. Frankly,
don't really want to go there again and spend too much time (at least
not in the context of this patch series).

So here is what I suggest: can we approach this one-step-at-a-time?
This patch-set is a major step as it is, and it takes a lot of time to
get it merged. What you suggest makes sense but might have some
implications (even architectural) when trying to implement that. Can
we do that in another series?

> [..]
>
> > diff --git a/common/image-android.c b/common/image-android.c
> > index 3564a64221..5e721a27a7 100644
> > --- a/common/image-android.c
> > +++ b/common/image-android.c
> > @@ -6,10 +6,12 @@
> >  #include <common.h>
> >  #include <env.h>
> >  #include <image.h>
> > +#include <image-android-dt.h>
> >  #include <android_image.h>
> >  #include <malloc.h>
> >  #include <errno.h>
> >  #include <asm/unaligned.h>
> > +#include <mapmem.h>
> >
> >  #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR    0x10008000
> >
> > @@ -195,6 +197,122 @@ int android_image_get_second(const struct andr_img_hdr *hdr,
> >       return 0;
> >  }
> >
> > +/**
> > + * android_image_get_dtb_img_addr() - Get the address of DTB area in boot image.
> > + * @hdr_addr: Boot image header address
> > + * @addr: Will contain the address of DTB area in boot image
> > + *
> > + * Return: true on success or false on fail.
> > + */
> > +static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr)
> > +{
> > +     const struct andr_img_hdr *hdr;
> > +     ulong dtb_img_addr;
> > +     bool res = true;
> > +
> > +     hdr = map_sysmem(hdr_addr, sizeof(*hdr));
> > +     if (android_image_check_header(hdr)) {
> > +             printf("Error: Boot Image header is incorrect\n");
> > +             res = false;
> > +             goto exit;
> > +     }
> > +
> > +     if (hdr->header_version < 2) {
> > +             printf("Error: header_version must be >= 2 to get dtb\n");
> > +             res = false;
> > +             goto exit;
> > +     }
> > +
> > +     if (hdr->dtb_size == 0) {
> > +             printf("Error: dtb_size is 0\n");
> > +             res = false;
> > +             goto exit;
> > +     }
> > +
> > +     /* Calculate the address of DTB area in boot image */
> > +     dtb_img_addr = hdr_addr;
> > +     dtb_img_addr += hdr->page_size;
> > +     dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
> > +     dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
> > +     dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size);
> > +     dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
> > +
> > +     if (addr)
> > +             *addr = dtb_img_addr;
>
> In this recent series, I noticed a consistent preference towards
> doing a lot of processing with returning nothing to the caller in
> case of an invalid argument. Is this by choice?
>

In this particular case, this is probably just a leftover from
copy-paste from other DTBO related function, where such a parameter is
optional. Here we can just remove that "if" condition, I guess... Not
sure it's a major issue though. If you see any broken logic or
incorrect behavior, please comment in place.

Otherwise, if there are no major concerns, I suggest to take it as is,
and adding other desired features in other series. Please add your
Reviewed-by tag if you agree.

Thanks!

> --
> Best Regards,
> Eugeniu
Eugeniu Rosca Dec. 3, 2019, 1:59 p.m. UTC | #3
Hi Sam,

On Mon, Dec 02, 2019 at 07:19:53PM +0200, Sam Protsenko wrote:
> On Tue, Oct 29, 2019 at 3:49 AM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
> > On Wed, Oct 23, 2019 at 05:34:20PM +0300, Sam Protsenko wrote:
> > > Android Boot Image v2 adds "DTB" payload (and corresponding field in the
> > > image header). Provide functions for its handling:
> >
> > I believe this totally new degree of freedom brought by "Android Boot
> > Image v2" might unintentionally make some users more unhappy [0], since
> > it enables yet another way of passing a DTB to the Android kernel.
> >
> > It looks to me that there are at least three valid design choices for
> > DTB storage/passing which platform maintainers have to consider:
> >  A. Android Image second area [1-2]
> >  B. Dedicated DTB/DTBO partitions on a block device
> >  C. DTB area in Android Image v2
> >
> > While there are some major disadvantages for [A][1-2], [B] and [C] look
> > more or less equivalent and will most likely only differ in the tooling
> > used to generate and extract the useful/relevant artifacts.
> >
> > Not to mention that hybrids [B+C] are also possible.
> > Which solution should we pick as a long-term one?
> 
> My opinion is next: we should provide means (commands) to achieve any
> of [A,B,C] options. Then user (I mean, U-Boot developer who implements
> boot for each particular board) should decide which approach to use.

Fine. Thanks. But I hope you also keep in mind that the more design
choices you make available to the users (especially if redundant):
 - the more test coverage you will have to accomplish, which translates
   to more requests from Simon for test development and maintenance
 - the greater the attack surface/vector, i.e. increased likelihood for
   CVEs and the like

> Also [D] FIT image can be used instead of Android Boot Image. But we
> should remember that Google requires *mandatory* for all *new* devices
> (starting with Android 10) to stick with [C] approach only. Option [B]
> might be harder to handle from AVB verification point of view.

That's useful feedback. Thanks.

> Btw,
> when we come to "boot_android" command, I think we'll need to
> implement only officially recommended boot method. Maybe provide a
> param to choose whether to do Android-9 or Android-10 boot scheme.
> 
> Anyway, the short answer is: we should provide a bunch of isolated
> commands to allow the user to implement any boot method.

Agreed with the above warnings.

[..]

> >  - I would try to avoid wiring the same compilation unit to Kbuild
> >    (e.g. image-android-dt.o) via multiple Kconfig symbols
> >    (CONFIG_ANDROID_BOOT_IMAGE and CONFIG_CMD_DTIMG) since this makes
> >    the relationship between the CONFIG symbols unclear. As a user, I
> >    would like to see a simple mapping between compiled objects and
> >    Kconfig symbols, eventually reflecting a hierarchy/dependency:
> >
> >    config ANDROID_BOOT_IMAGE
> >       select ANDROID_BOOT_IMAGE_DT
> >
> >    config DTIMG
> >       select ANDROID_BOOT_IMAGE_DT
> >
> 
> I thought about that 4 months ago when implementing this patch, even
> experimented with that. But decided to just add image-android-dt.o in
> Makefile instead, don't remember for what reason exactly. Frankly,
> don't really want to go there again and spend too much time (at least
> not in the context of this patch series).
> 
> So here is what I suggest: can we approach this one-step-at-a-time?
> This patch-set is a major step as it is, and it takes a lot of time to
> get it merged. What you suggest makes sense but might have some
> implications (even architectural) when trying to implement that. Can
> we do that in another series?

I totally agree with the following:
 - This series is a major step forward. Many thanks for this effort.
 - Bikeshedding and minor findings can be postponed.

However, for the sake of a non-chaotic git history and the right degree
of intuitiveness in the usage of all newly developed commands, I see
below review points as _major_ and better be fixed before merging:
 - The name of the "bootimg" command intrudes too much into the U-Boot
   global namespace. This has been flagged by Simon [*]
   with no reply from you yet. Do you plan to provide feedback?
 - Kconfig wiring and naming. IMHO the right decisions have to be made
   whenever new files are added to Kbuild. It is like placing the right
   pipe infrastructure into the basement of the building. Why would you
   want to make it twice? Renaming/deleting/relocating Kconfig symbols
   makes comparing [**] the configurations of distinct U-Boot/Linux
   versions pretty painful later on.
 - Agreeing on the _right_ usage scheme/pattern for any newly developed
   U-Boot command is incredibly important right from the start. What
   makes me so confident in stating that and do I have doubts about the
   current "bootimg" usage pattern? Yes, I do. That's because the
   "bootimg" arguments follow more or less the  "dtimg" usage pattern.
   My recent series [***], updating the "dtimg" Android command,
   _struggled_ with finding an intuitive way to get the DTB/DTBO based
   on user-provided "id" and/or "rev" fields, as documented in
   https://source.android.com/devices/architecture/dto/partitions . To
   give an example, making the <index> argument mandatory in
   "bootimg get_dtb_file <index> <addr_var> [size_var]" is probably not
   the best choice simply b/c searching/retrieving DTB/DTBO by absolute
   <index> in the image is just one possible search criteria. Our
   customers would _not_ like to use this criteria for obvious reasons.
   They would like to retrieve DTB/DTBO by "id" and "rev" field values.
   So, how do you interpret <index> in these latter cases if you keep
   it as a required argument? Or should we treat <index> as an optional
   parameter when "id" and/or "rev" are provided? I hope you can get a
   feeling of how important it is to agree on the usage concept for
   "bootimg" right now, not later.

[*] https://patchwork.ozlabs.org/patch/1182212/#2291600
[**] https://patchwork.kernel.org/patch/10230207/#21524437
[***] https://patchwork.ozlabs.org/cover/1202575/
     ("cmd: dtimg: Enhance with --id and --rev options (take #1)")
Sam Protsenko Dec. 3, 2019, 7:24 p.m. UTC | #4
Hi,

On Tue, Dec 3, 2019 at 3:59 PM Eugeniu Rosca <roscaeugeniu@gmail.com> wrote:
>
> Hi Sam,
>
> On Mon, Dec 02, 2019 at 07:19:53PM +0200, Sam Protsenko wrote:
> > On Tue, Oct 29, 2019 at 3:49 AM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
> > > On Wed, Oct 23, 2019 at 05:34:20PM +0300, Sam Protsenko wrote:
> > > > Android Boot Image v2 adds "DTB" payload (and corresponding field in the
> > > > image header). Provide functions for its handling:
> > >
> > > I believe this totally new degree of freedom brought by "Android Boot
> > > Image v2" might unintentionally make some users more unhappy [0], since
> > > it enables yet another way of passing a DTB to the Android kernel.
> > >
> > > It looks to me that there are at least three valid design choices for
> > > DTB storage/passing which platform maintainers have to consider:
> > >  A. Android Image second area [1-2]
> > >  B. Dedicated DTB/DTBO partitions on a block device
> > >  C. DTB area in Android Image v2
> > >
> > > While there are some major disadvantages for [A][1-2], [B] and [C] look
> > > more or less equivalent and will most likely only differ in the tooling
> > > used to generate and extract the useful/relevant artifacts.
> > >
> > > Not to mention that hybrids [B+C] are also possible.
> > > Which solution should we pick as a long-term one?
> >
> > My opinion is next: we should provide means (commands) to achieve any
> > of [A,B,C] options. Then user (I mean, U-Boot developer who implements
> > boot for each particular board) should decide which approach to use.
>
> Fine. Thanks. But I hope you also keep in mind that the more design
> choices you make available to the users (especially if redundant):
>  - the more test coverage you will have to accomplish, which translates
>    to more requests from Simon for test development and maintenance
>  - the greater the attack surface/vector, i.e. increased likelihood for
>    CVEs and the like
>
> > Also [D] FIT image can be used instead of Android Boot Image. But we
> > should remember that Google requires *mandatory* for all *new* devices
> > (starting with Android 10) to stick with [C] approach only. Option [B]
> > might be harder to handle from AVB verification point of view.
>
> That's useful feedback. Thanks.
>
> > Btw,
> > when we come to "boot_android" command, I think we'll need to
> > implement only officially recommended boot method. Maybe provide a
> > param to choose whether to do Android-9 or Android-10 boot scheme.
> >
> > Anyway, the short answer is: we should provide a bunch of isolated
> > commands to allow the user to implement any boot method.
>
> Agreed with the above warnings.
>
> [..]
>
> > >  - I would try to avoid wiring the same compilation unit to Kbuild
> > >    (e.g. image-android-dt.o) via multiple Kconfig symbols
> > >    (CONFIG_ANDROID_BOOT_IMAGE and CONFIG_CMD_DTIMG) since this makes
> > >    the relationship between the CONFIG symbols unclear. As a user, I
> > >    would like to see a simple mapping between compiled objects and
> > >    Kconfig symbols, eventually reflecting a hierarchy/dependency:
> > >
> > >    config ANDROID_BOOT_IMAGE
> > >       select ANDROID_BOOT_IMAGE_DT
> > >
> > >    config DTIMG
> > >       select ANDROID_BOOT_IMAGE_DT
> > >
> >
> > I thought about that 4 months ago when implementing this patch, even
> > experimented with that. But decided to just add image-android-dt.o in
> > Makefile instead, don't remember for what reason exactly. Frankly,
> > don't really want to go there again and spend too much time (at least
> > not in the context of this patch series).
> >
> > So here is what I suggest: can we approach this one-step-at-a-time?
> > This patch-set is a major step as it is, and it takes a lot of time to
> > get it merged. What you suggest makes sense but might have some
> > implications (even architectural) when trying to implement that. Can
> > we do that in another series?
>
> I totally agree with the following:
>  - This series is a major step forward. Many thanks for this effort.
>  - Bikeshedding and minor findings can be postponed.
>
> However, for the sake of a non-chaotic git history and the right degree
> of intuitiveness in the usage of all newly developed commands, I see
> below review points as _major_ and better be fixed before merging:
>  - The name of the "bootimg" command intrudes too much into the U-Boot
>    global namespace. This has been flagged by Simon [*]
>    with no reply from you yet. Do you plan to provide feedback?

Already renamed to 'abootimg' and replied to Simon. Will send v3 soon.

>  - Kconfig wiring and naming. IMHO the right decisions have to be made
>    whenever new files are added to Kbuild. It is like placing the right
>    pipe infrastructure into the basement of the building. Why would you
>    want to make it twice? Renaming/deleting/relocating Kconfig symbols
>    makes comparing [**] the configurations of distinct U-Boot/Linux
>    versions pretty painful later on.

Ok, will look into that tomorrow. And either will improve that, or at
least will provide some proper explanation as to why I don't want to
do so :)

Do I understand correctly that your point is: we should be able to
disable all DTBO related code when using 'bootimg' command (or just
when enabling ANDROID_BOOT_IMAGE)?

>  - Agreeing on the _right_ usage scheme/pattern for any newly developed
>    U-Boot command is incredibly important right from the start. What
>    makes me so confident in stating that and do I have doubts about the
>    current "bootimg" usage pattern? Yes, I do. That's because the
>    "bootimg" arguments follow more or less the  "dtimg" usage pattern.
>    My recent series [***], updating the "dtimg" Android command,
>    _struggled_ with finding an intuitive way to get the DTB/DTBO based
>    on user-provided "id" and/or "rev" fields, as documented in
>    https://source.android.com/devices/architecture/dto/partitions . To
>    give an example, making the <index> argument mandatory in
>    "bootimg get_dtb_file <index> <addr_var> [size_var]" is probably not
>    the best choice simply b/c searching/retrieving DTB/DTBO by absolute
>    <index> in the image is just one possible search criteria. Our
>    customers would _not_ like to use this criteria for obvious reasons.
>    They would like to retrieve DTB/DTBO by "id" and "rev" field values.
>    So, how do you interpret <index> in these latter cases if you keep
>    it as a required argument? Or should we treat <index> as an optional
>    parameter when "id" and/or "rev" are provided? I hope you can get a
>    feeling of how important it is to agree on the usage concept for
>    "bootimg" right now, not later.
>

Agreed. Do you have some particular way of making 'bootimg' more
extensible? I'd like to keep index way as well (because if dtb files
are just concatenated this is probably the only way to specify it).
But I can change 'bootimg' interface to something like:

    bootimg get_dtb_file index <index> <addr_var> [size_var]
    bootimg get_dtb_file id <id> <addr_var> [size_var]
    bootimg get_dtb_file rev <rev> <addr_var> [size_var]

This approach seems to be easy to extend in future. That would be ok
with you, or you see some better way to fix this?

As for 'dtimg' command: after giving it some thought, I think not much
people using it yet. So in this particular case I don't have some
strong preference, and if you think the 'dtimg' interface is ugly, and
it overcomes "don't break interfaces" rule, maybe now is a good time
to rework it (before it gets widely used). Anyway, let's continue
'dtimg' related discussion in dtimg thread, it's kinda off-topic here.

Thanks for detailed review!

> [*] https://patchwork.ozlabs.org/patch/1182212/#2291600
> [**] https://patchwork.kernel.org/patch/10230207/#21524437
> [***] https://patchwork.ozlabs.org/cover/1202575/
>      ("cmd: dtimg: Enhance with --id and --rev options (take #1)")
>
> --
> Best Regards,
> Eugeniu
diff mbox series

Patch

diff --git a/common/Makefile b/common/Makefile
index 302d8beaf3..7e5f5058b3 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -108,7 +108,7 @@  endif
 
 obj-y += image.o
 obj-$(CONFIG_ANDROID_AB) += android_ab.o
-obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
+obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
 obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
 obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o
diff --git a/common/image-android.c b/common/image-android.c
index 3564a64221..5e721a27a7 100644
--- a/common/image-android.c
+++ b/common/image-android.c
@@ -6,10 +6,12 @@ 
 #include <common.h>
 #include <env.h>
 #include <image.h>
+#include <image-android-dt.h>
 #include <android_image.h>
 #include <malloc.h>
 #include <errno.h>
 #include <asm/unaligned.h>
+#include <mapmem.h>
 
 #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR	0x10008000
 
@@ -195,6 +197,122 @@  int android_image_get_second(const struct andr_img_hdr *hdr,
 	return 0;
 }
 
+/**
+ * android_image_get_dtb_img_addr() - Get the address of DTB area in boot image.
+ * @hdr_addr: Boot image header address
+ * @addr: Will contain the address of DTB area in boot image
+ *
+ * Return: true on success or false on fail.
+ */
+static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr)
+{
+	const struct andr_img_hdr *hdr;
+	ulong dtb_img_addr;
+	bool res = true;
+
+	hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+	if (android_image_check_header(hdr)) {
+		printf("Error: Boot Image header is incorrect\n");
+		res = false;
+		goto exit;
+	}
+
+	if (hdr->header_version < 2) {
+		printf("Error: header_version must be >= 2 to get dtb\n");
+		res = false;
+		goto exit;
+	}
+
+	if (hdr->dtb_size == 0) {
+		printf("Error: dtb_size is 0\n");
+		res = false;
+		goto exit;
+	}
+
+	/* Calculate the address of DTB area in boot image */
+	dtb_img_addr = hdr_addr;
+	dtb_img_addr += hdr->page_size;
+	dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
+	dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
+	dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size);
+	dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
+
+	if (addr)
+		*addr = dtb_img_addr;
+
+exit:
+	unmap_sysmem(hdr);
+	return res;
+}
+
+/**
+ * android_image_get_dtb_by_index() - Get address and size of file in DTB area.
+ * @hdr_addr: Boot image header address
+ * @index: Index of desired DTB in DTB area (starting from 0)
+ * @addr: If not NULL, will contain address to specified DTB
+ * @size: If not NULL, will contain size of specified DTB
+ *
+ * Get the address and size of DTB file by its index in DTB area of Android
+ * Boot Image in RAM.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
+				    u32 *size)
+{
+	const struct andr_img_hdr *hdr;
+	bool res;
+	ulong dtb_img_addr;	/* address of DTB part in boot image */
+	u32 dtb_img_size;	/* size of DTB payload in boot image */
+	ulong dtb_addr;		/* address of DTB file with specified index  */
+	u32 i;			/* index iterator */
+
+	res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
+	if (!res)
+		return false;
+
+	/* Check if DTB area of boot image is in DTBO format */
+	if (android_dt_check_header(dtb_img_addr)) {
+		return android_dt_get_fdt_by_index(dtb_img_addr, index, addr,
+						   size);
+	}
+
+	/* Find out the address of DTB with specified index in concat blobs */
+	hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+	dtb_img_size = hdr->dtb_size;
+	unmap_sysmem(hdr);
+	i = 0;
+	dtb_addr = dtb_img_addr;
+	while (dtb_addr < dtb_img_addr + dtb_img_size) {
+		const struct fdt_header *fdt;
+		u32 dtb_size;
+
+		fdt = map_sysmem(dtb_addr, sizeof(*fdt));
+		if (fdt_check_header(fdt) != 0) {
+			unmap_sysmem(fdt);
+			printf("Error: Invalid FDT header for index %u\n", i);
+			return false;
+		}
+
+		dtb_size = fdt_totalsize(fdt);
+		unmap_sysmem(fdt);
+
+		if (i == index) {
+			if (size)
+				*size = dtb_size;
+			if (addr)
+				*addr = dtb_addr;
+			return true;
+		}
+
+		dtb_addr += dtb_size;
+		++i;
+	}
+
+	printf("Error: Index is out of bounds (%u/%u)\n", index, i);
+	return false;
+}
+
 #if !defined(CONFIG_SPL_BUILD)
 /**
  * android_print_contents - prints out the contents of the Android format image
@@ -246,4 +364,101 @@  void android_print_contents(const struct andr_img_hdr *hdr)
 		printf("%sdtb addr:             %llx\n", p, hdr->dtb_addr);
 	}
 }
+
+static bool android_image_print_dtb_info(const struct fdt_header *fdt,
+					 u32 index)
+{
+	int root_node_off;
+	u32 fdt_size;
+	const char *model;
+	const char *compatible;
+
+	root_node_off = fdt_path_offset(fdt, "/");
+	if (root_node_off < 0) {
+		printf("Error: Root node not found\n");
+		return false;
+	}
+
+	fdt_size = fdt_totalsize(fdt);
+	compatible = fdt_getprop(fdt, root_node_off, "compatible",
+				 NULL);
+	model = fdt_getprop(fdt, root_node_off, "model", NULL);
+
+	printf(" - DTB #%u:\n", index);
+	printf("           (DTB)size = %d\n", fdt_size);
+	printf("          (DTB)model = %s\n", model ? model : "(unknown)");
+	printf("     (DTB)compatible = %s\n",
+	       compatible ? compatible : "(unknown)");
+
+	return true;
+}
+
+/**
+ * android_image_print_dtb_contents() - Print info for DTB files in DTB area.
+ * @hdr_addr: Boot image header address
+ *
+ * DTB payload in Android Boot Image v2+ can be in one of following formats:
+ *   1. Concatenated DTB files
+ *   2. Android DTBO format (see CONFIG_CMD_DTIMG for details)
+ *
+ * This function does next:
+ *   1. Prints out the format used in DTB area
+ *   2. Iterates over all DTB files in DTB area and prints out the info for
+ *      each file.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_print_dtb_contents(ulong hdr_addr)
+{
+	const struct andr_img_hdr *hdr;
+	bool res;
+	ulong dtb_img_addr;	/* address of DTB part in boot image */
+	u32 dtb_img_size;	/* size of DTB payload in boot image */
+	ulong dtb_addr;		/* address of DTB file with specified index  */
+	u32 i;			/* index iterator */
+
+	res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
+	if (!res)
+		return false;
+
+	/* Check if DTB area of boot image is in DTBO format */
+	if (android_dt_check_header(dtb_img_addr)) {
+		printf("## DTB area contents (DTBO format):\n");
+		android_dt_print_contents(dtb_img_addr);
+		return true;
+	}
+
+	printf("## DTB area contents (concat format):\n");
+
+	/* Iterate over concatenated DTB files */
+	hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+	dtb_img_size = hdr->dtb_size;
+	unmap_sysmem(hdr);
+	i = 0;
+	dtb_addr = dtb_img_addr;
+	while (dtb_addr < dtb_img_addr + dtb_img_size) {
+		const struct fdt_header *fdt;
+		u32 dtb_size;
+
+		fdt = map_sysmem(dtb_addr, sizeof(*fdt));
+		if (fdt_check_header(fdt) != 0) {
+			unmap_sysmem(fdt);
+			printf("Error: Invalid FDT header for index %u\n", i);
+			return false;
+		}
+
+		res = android_image_print_dtb_info(fdt, i);
+		if (!res) {
+			unmap_sysmem(fdt);
+			return false;
+		}
+
+		dtb_size = fdt_totalsize(fdt);
+		unmap_sysmem(fdt);
+		dtb_addr += dtb_size;
+		++i;
+	}
+
+	return true;
+}
 #endif
diff --git a/include/image.h b/include/image.h
index c1065c06f9..042eb89a0f 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1333,10 +1333,15 @@  int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
 			      ulong *rd_data, ulong *rd_len);
 int android_image_get_second(const struct andr_img_hdr *hdr,
 			      ulong *second_data, ulong *second_len);
+bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
+				    u32 *size);
 ulong android_image_get_end(const struct andr_img_hdr *hdr);
 ulong android_image_get_kload(const struct andr_img_hdr *hdr);
 ulong android_image_get_kcomp(const struct andr_img_hdr *hdr);
 void android_print_contents(const struct andr_img_hdr *hdr);
+#if !defined(CONFIG_SPL_BUILD)
+bool android_image_print_dtb_contents(ulong hdr_addr);
+#endif
 
 #endif /* CONFIG_ANDROID_BOOT_IMAGE */