[PATCH v2 0/3] image: android: misc fixes when using on Qualcomm platforms

When trying to use the Android boot image with header version 2 on recent Qualcomm platforms, we get into some troubles.
First the kernel in-place address can be > 32bit, then since we use the Android mkbootimg, it uses the default load address which isn't big enough to uncompress the kernel.
Finally, the ramdisk also uses a default load address, and it should be taken in account like for the kernel address.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- Changes in v2: - Fix patch 2 prefix - Fix patch 3 commit msg - Fix patch 3 behavior when using boot image header version > 2, use the original ramdisk_ptr - Link to v1: https://lore.kernel.org/r/20241016-topic-fastboot-fixes-mkbootimg-v1-0-94fd9...
--- Neil Armstrong (3): image: android: use ulong for kernel address image: android: do not boot XIP when kernel is compressed image: android: handle ramdisk default address
boot/image-android.c | 62 +++++++++++++++++++++++++++++++++++++------------ include/android_image.h | 2 +- 2 files changed, 48 insertions(+), 16 deletions(-) --- base-commit: d5cab0d6adc26ec1bbd45c2fed101184d04454ae change-id: 20241016-topic-fastboot-fixes-mkbootimg-8d73ab93db3d
Best regards,

When booting with platforms having > 4GiB of memory, the kernel physical address can be more than 32bits.
Use ulong like all the other addresses, and fix the print to show the > 32bits address numbers.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- boot/image-android.c | 4 ++-- include/android_image.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/boot/image-android.c b/boot/image-android.c index e74dd498a305566e42aa235b45c22995e21ca64b..bb5f4f84487d40e0cf24dc3b57042993967e66d5 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -256,7 +256,7 @@ int android_image_get_kernel(const void *hdr, ulong *os_data, ulong *os_len) { struct andr_image_data img_data = {0}; - u32 kernel_addr; + ulong kernel_addr; const struct legacy_img_hdr *ihdr;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) @@ -275,7 +275,7 @@ int android_image_get_kernel(const void *hdr, if (strlen(andr_tmp_str)) printf("Android's image name: %s\n", andr_tmp_str);
- printf("Kernel load addr 0x%08x size %u KiB\n", + printf("Kernel load addr 0x%08lx size %u KiB\n", kernel_addr, DIV_ROUND_UP(img_data.kernel_size, 1024));
int len = 0; diff --git a/include/android_image.h b/include/android_image.h index d503c980b233bf31cd12a246ff1570544597a1c7..96820709b42830c7ce4cb753687da373936253a7 100644 --- a/include/android_image.h +++ b/include/android_image.h @@ -348,7 +348,7 @@ struct andr_image_data { ulong bootconfig_addr; /* bootconfig image address */ ulong bootconfig_size; /* bootconfig image size */
- u32 kernel_addr; /* physical load addr */ + ulong kernel_addr; /* physical load addr */ ulong ramdisk_addr; /* physical load addr */ ulong ramdisk_ptr; /* ramdisk address */ ulong dtb_load_addr; /* physical load address for DTB image */

Hi Neil,
Thank you for the patch.
On jeu., oct. 17, 2024 at 16:44, Neil Armstrong neil.armstrong@linaro.org wrote:
When booting with platforms having > 4GiB of memory, the kernel physical address can be more than 32bits.
Use ulong like all the other addresses, and fix the print to show the > 32bits address numbers.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org
Reviewed-by: Mattijs Korpershoek mkorpershoek@baylibre.com
boot/image-android.c | 4 ++-- include/android_image.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/boot/image-android.c b/boot/image-android.c index e74dd498a305566e42aa235b45c22995e21ca64b..bb5f4f84487d40e0cf24dc3b57042993967e66d5 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -256,7 +256,7 @@ int android_image_get_kernel(const void *hdr, ulong *os_data, ulong *os_len) { struct andr_image_data img_data = {0};
- u32 kernel_addr;
ulong kernel_addr; const struct legacy_img_hdr *ihdr;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data))
@@ -275,7 +275,7 @@ int android_image_get_kernel(const void *hdr, if (strlen(andr_tmp_str)) printf("Android's image name: %s\n", andr_tmp_str);
- printf("Kernel load addr 0x%08x size %u KiB\n",
printf("Kernel load addr 0x%08lx size %u KiB\n", kernel_addr, DIV_ROUND_UP(img_data.kernel_size, 1024));
int len = 0;
diff --git a/include/android_image.h b/include/android_image.h index d503c980b233bf31cd12a246ff1570544597a1c7..96820709b42830c7ce4cb753687da373936253a7 100644 --- a/include/android_image.h +++ b/include/android_image.h @@ -348,7 +348,7 @@ struct andr_image_data { ulong bootconfig_addr; /* bootconfig image address */ ulong bootconfig_size; /* bootconfig image size */
- u32 kernel_addr; /* physical load addr */
- ulong kernel_addr; /* physical load addr */ ulong ramdisk_addr; /* physical load addr */ ulong ramdisk_ptr; /* ramdisk address */ ulong dtb_load_addr; /* physical load address for DTB image */
-- 2.34.1

When trying to boot an android boot image with a compressed kernel, if the kernel is used in-place because it was created with mkbootimg, the space will be too small to properly uncompress.
Take in account the compressed state, and if compressed use the kernel_addr_r which should be big enough.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- boot/image-android.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/boot/image-android.c b/boot/image-android.c index bb5f4f84487d40e0cf24dc3b57042993967e66d5..3adcc69a392f74ae64f3fbcf1b85204f60ac9aff 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -208,7 +208,8 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, return true; }
-static ulong android_image_get_kernel_addr(struct andr_image_data *img_data) +static ulong android_image_get_kernel_addr(struct andr_image_data *img_data, + ulong comp) { /* * All the Android tools that generate a boot.img use this @@ -221,8 +222,11 @@ static ulong android_image_get_kernel_addr(struct andr_image_data *img_data) * * Otherwise, we will return the actual value set by the user. */ - if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) - return img_data->kernel_ptr; + if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) { + if (comp == IH_COMP_NONE) + return img_data->kernel_ptr; + return env_get_ulong("kernel_addr_r", 16, 0); + }
/* * abootimg creates images where all load addresses are 0 @@ -258,11 +262,14 @@ int android_image_get_kernel(const void *hdr, struct andr_image_data img_data = {0}; ulong kernel_addr; const struct legacy_img_hdr *ihdr; + ulong comp;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) return -EINVAL;
- kernel_addr = android_image_get_kernel_addr(&img_data); + comp = android_image_get_kcomp(hdr, vendor_boot_img); + + kernel_addr = android_image_get_kernel_addr(&img_data, comp); ihdr = (const struct legacy_img_hdr *)img_data.kernel_ptr;
/* @@ -359,11 +366,14 @@ ulong android_image_get_kload(const void *hdr, const void *vendor_boot_img) { struct andr_image_data img_data; + ulong comp;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) return -EINVAL;
- return android_image_get_kernel_addr(&img_data); + comp = android_image_get_kcomp(hdr, vendor_boot_img); + + return android_image_get_kernel_addr(&img_data, comp); }
ulong android_image_get_kcomp(const void *hdr,

Hi Neil,
Thank you for the patch.
On jeu., oct. 17, 2024 at 16:44, Neil Armstrong neil.armstrong@linaro.org wrote:
When trying to boot an android boot image with a compressed kernel, if the kernel is used in-place because it was created with mkbootimg, the space will be too small to properly uncompress.
Take in account the compressed state, and if compressed use the kernel_addr_r which should be big enough.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org
Reviewed-by: Mattijs Korpershoek mkorpershoek@baylibre.com
boot/image-android.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/boot/image-android.c b/boot/image-android.c index bb5f4f84487d40e0cf24dc3b57042993967e66d5..3adcc69a392f74ae64f3fbcf1b85204f60ac9aff 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -208,7 +208,8 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, return true; }
-static ulong android_image_get_kernel_addr(struct andr_image_data *img_data) +static ulong android_image_get_kernel_addr(struct andr_image_data *img_data,
ulong comp)
{ /* * All the Android tools that generate a boot.img use this @@ -221,8 +222,11 @@ static ulong android_image_get_kernel_addr(struct andr_image_data *img_data) * * Otherwise, we will return the actual value set by the user. */
- if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR)
return img_data->kernel_ptr;
if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) {
if (comp == IH_COMP_NONE)
return img_data->kernel_ptr;
return env_get_ulong("kernel_addr_r", 16, 0);
}
/*
- abootimg creates images where all load addresses are 0
@@ -258,11 +262,14 @@ int android_image_get_kernel(const void *hdr, struct andr_image_data img_data = {0}; ulong kernel_addr; const struct legacy_img_hdr *ihdr;
ulong comp;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) return -EINVAL;
- kernel_addr = android_image_get_kernel_addr(&img_data);
comp = android_image_get_kcomp(hdr, vendor_boot_img);
kernel_addr = android_image_get_kernel_addr(&img_data, comp); ihdr = (const struct legacy_img_hdr *)img_data.kernel_ptr;
/*
@@ -359,11 +366,14 @@ ulong android_image_get_kload(const void *hdr, const void *vendor_boot_img) { struct andr_image_data img_data;
ulong comp;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) return -EINVAL;
- return android_image_get_kernel_addr(&img_data);
- comp = android_image_get_kcomp(hdr, vendor_boot_img);
- return android_image_get_kernel_addr(&img_data, comp);
}
ulong android_image_get_kcomp(const void *hdr,
-- 2.34.1

The two tools that create android boot images, mkbootimg and the fastboot client, set the kernel address by default to 0x11008000.
U-boot always honors this field, and will try to copy the ramdisk to whatever value is set in the header, which won't be mapped to the actual RAM on most platforms, resulting in the kernel obviously not booting.
All the targets in U-Boot right now will download the android boot image to CONFIG_SYS_LOAD_ADDR, which means that it will already have been downloaded to some location that is suitable to use the ramdisk in-place for header version 0 to 2. For header version 3 and later, the ramdisk can't be used in-place to use ramdisk_addr_r in this case.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org --- boot/image-android.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-)
diff --git a/boot/image-android.c b/boot/image-android.c index 3adcc69a392f74ae64f3fbcf1b85204f60ac9aff..cd01278f211d63262f2bdad7aa1176e2c1bbfedd 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -14,6 +14,7 @@ #include <linux/libfdt.h>
#define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000 +#define ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR 0x11000000
static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
@@ -405,9 +406,25 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img,
if (!img_data.ramdisk_size) return -ENOENT; - + /* + * Android tools can generate a boot.img with default load address + * or 0, even though it doesn't really make a lot of sense, and it + * might be valid on some platforms, we treat that address as + * the default value for this field, and try to pass ramdisk + * in place if possible. + */ if (img_data.header_version > 2) { - ramdisk_ptr = img_data.ramdisk_addr; + /* Ramdisk can't be used in-place, copy it to ramdisk_addr_r */ + if (img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR) { + ramdisk_ptr = env_get_ulong("ramdisk_addr_r", 16, 0); + if (!ramdisk_ptr) { + printf("Invalid ramdisk_addr_r to copy ramdisk into\n"); + return -EINVAL; + } + } else { + ramdisk_ptr = img_data.ramdisk_addr; + } + *rd_data = ramdisk_ptr; memcpy((void *)(ramdisk_ptr), (void *)img_data.vendor_ramdisk_ptr, img_data.vendor_ramdisk_size); ramdisk_ptr += img_data.vendor_ramdisk_size; @@ -420,15 +437,20 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, img_data.bootconfig_size); } } else { - ramdisk_ptr = img_data.ramdisk_addr; - memcpy((void *)(ramdisk_ptr), (void *)img_data.ramdisk_ptr, - img_data.ramdisk_size); + /* Ramdisk can be used in-place, use current ptr */ + if (img_data.ramdisk_addr == 0 || + img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR) { + *rd_data = img_data.ramdisk_ptr; + } else { + ramdisk_ptr = img_data.ramdisk_addr; + *rd_data = ramdisk_ptr; + memcpy((void *)(ramdisk_ptr), (void *)img_data.ramdisk_ptr, + img_data.ramdisk_size); + } }
printf("RAM disk load addr 0x%08lx size %u KiB\n", - img_data.ramdisk_addr, DIV_ROUND_UP(img_data.ramdisk_size, 1024)); - - *rd_data = img_data.ramdisk_addr; + *rd_data, DIV_ROUND_UP(img_data.ramdisk_size, 1024));
*rd_len = img_data.ramdisk_size; return 0;

Hi Neil,
Thank you for the patch.
On jeu., oct. 17, 2024 at 16:44, Neil Armstrong neil.armstrong@linaro.org wrote:
The two tools that create android boot images, mkbootimg and the fastboot client, set the kernel address by default to 0x11008000.
U-boot always honors this field, and will try to copy the ramdisk to whatever value is set in the header, which won't be mapped to the actual RAM on most platforms, resulting in the kernel obviously not booting.
All the targets in U-Boot right now will download the android boot image to CONFIG_SYS_LOAD_ADDR, which means that it will already have been downloaded to some location that is suitable to use the ramdisk in-place for header version 0 to 2. For header version 3 and later, the ramdisk can't be used in-place to use ramdisk_addr_r in this case.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org
Reviewed-by: Mattijs Korpershoek mkorpershoek@baylibre.com
boot/image-android.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-)
diff --git a/boot/image-android.c b/boot/image-android.c index 3adcc69a392f74ae64f3fbcf1b85204f60ac9aff..cd01278f211d63262f2bdad7aa1176e2c1bbfedd 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -14,6 +14,7 @@ #include <linux/libfdt.h>
#define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000 +#define ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR 0x11000000
static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
@@ -405,9 +406,25 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img,
if (!img_data.ramdisk_size) return -ENOENT;
- /*
* Android tools can generate a boot.img with default load address
* or 0, even though it doesn't really make a lot of sense, and it
* might be valid on some platforms, we treat that address as
* the default value for this field, and try to pass ramdisk
* in place if possible.
if (img_data.header_version > 2) {*/
ramdisk_ptr = img_data.ramdisk_addr;
/* Ramdisk can't be used in-place, copy it to ramdisk_addr_r */
if (img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR) {
ramdisk_ptr = env_get_ulong("ramdisk_addr_r", 16, 0);
if (!ramdisk_ptr) {
printf("Invalid ramdisk_addr_r to copy ramdisk into\n");
return -EINVAL;
}
} else {
ramdisk_ptr = img_data.ramdisk_addr;
}
memcpy((void *)(ramdisk_ptr), (void *)img_data.vendor_ramdisk_ptr, img_data.vendor_ramdisk_size); ramdisk_ptr += img_data.vendor_ramdisk_size;*rd_data = ramdisk_ptr;
@@ -420,15 +437,20 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, img_data.bootconfig_size); } } else {
ramdisk_ptr = img_data.ramdisk_addr;
memcpy((void *)(ramdisk_ptr), (void *)img_data.ramdisk_ptr,
img_data.ramdisk_size);
/* Ramdisk can be used in-place, use current ptr */
if (img_data.ramdisk_addr == 0 ||
img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR) {
*rd_data = img_data.ramdisk_ptr;
} else {
ramdisk_ptr = img_data.ramdisk_addr;
*rd_data = ramdisk_ptr;
memcpy((void *)(ramdisk_ptr), (void *)img_data.ramdisk_ptr,
img_data.ramdisk_size);
}
}
printf("RAM disk load addr 0x%08lx size %u KiB\n",
img_data.ramdisk_addr, DIV_ROUND_UP(img_data.ramdisk_size, 1024));
- *rd_data = img_data.ramdisk_addr;
*rd_data, DIV_ROUND_UP(img_data.ramdisk_size, 1024));
*rd_len = img_data.ramdisk_size; return 0;
-- 2.34.1

Hi,
thanks for this fixes. I just test this series on Khadas VIM3 with android image version 2 non A/B and AB, on TI AM62P with android image version 4 with AB, both boards boot fine.
Tested-by: Guillaume La Roque glaroque@baylibre.com
Guillaume
Le 17/10/2024 à 16:44, Neil Armstrong a écrit :
When trying to use the Android boot image with header version 2 on recent Qualcomm platforms, we get into some troubles.
First the kernel in-place address can be > 32bit, then since we use the Android mkbootimg, it uses the default load address which isn't big enough to uncompress the kernel.
Finally, the ramdisk also uses a default load address, and it should be taken in account like for the kernel address.
Signed-off-by: Neil Armstrong neil.armstrong@linaro.org
Changes in v2:
- Fix patch 2 prefix
- Fix patch 3 commit msg
- Fix patch 3 behavior when using boot image header version > 2, use the original ramdisk_ptr
- Link to v1: https://lore.kernel.org/r/20241016-topic-fastboot-fixes-mkbootimg-v1-0-94fd9...
Neil Armstrong (3): image: android: use ulong for kernel address image: android: do not boot XIP when kernel is compressed image: android: handle ramdisk default address
boot/image-android.c | 62 +++++++++++++++++++++++++++++++++++++------------ include/android_image.h | 2 +- 2 files changed, 48 insertions(+), 16 deletions(-)
base-commit: d5cab0d6adc26ec1bbd45c2fed101184d04454ae change-id: 20241016-topic-fastboot-fixes-mkbootimg-8d73ab93db3d
Best regards,

Hi,
On Thu, 17 Oct 2024 16:44:41 +0200, Neil Armstrong wrote:
When trying to use the Android boot image with header version 2 on recent Qualcomm platforms, we get into some troubles.
First the kernel in-place address can be > 32bit, then since we use the Android mkbootimg, it uses the default load address which isn't big enough to uncompress the kernel.
[...]
Thanks, Applied to https://source.denx.de/u-boot/custodians/u-boot-dfu (u-boot-dfu)
[1/3] image: android: use ulong for kernel address https://source.denx.de/u-boot/custodians/u-boot-dfu/-/commit/8f8e646d790199f... [2/3] image: android: do not boot XIP when kernel is compressed https://source.denx.de/u-boot/custodians/u-boot-dfu/-/commit/d5a85e8e95db57e... [3/3] image: android: handle ramdisk default address https://source.denx.de/u-boot/custodians/u-boot-dfu/-/commit/21e7fa0e3ac5997...
-- Mattijs
participants (3)
-
Guillaume LA ROQUE
-
Mattijs Korpershoek
-
Neil Armstrong