mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-02-27 19:11:04 +01:00
Add test to verify that androidboot.* parameters are correctly extracted from bootargs and appended to the bootconfig section when using 'abootimg get ramdisk' with boot image v4 and vendor_boot image. The test verifies: - androidboot.* parameters are removed from bootargs - They are appended to the bootconfig section in the ramdisk - Non-androidboot parameters remain in bootargs - The bootconfig trailer is properly updated Reviewed-by: Simon Glass <sjg@chromium.org> Signed-off-by: Guillaume La Roque (TI.com) <glaroque@baylibre.com> Reviewed-by: Mattijs Korpershoek <mkorpershoek@kernel.org> Link: https://lore.kernel.org/r/20260112-bootconfig-v5-5-79b242159ac7@baylibre.com [mkorpershoek: dropped whitespace changes from original patch] Signed-off-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
342 lines
14 KiB
Python
342 lines
14 KiB
Python
# SPDX-License-Identifier: GPL-2.0+
|
|
# Copyright (c) 2020
|
|
# Author: Sam Protsenko <joe.skb7@gmail.com>
|
|
|
|
# Test U-Boot's "abootimg" commands.
|
|
|
|
import os
|
|
import pytest
|
|
import utils
|
|
|
|
"""
|
|
These tests rely on disk image (boot.img), which is automatically created by
|
|
the test from the stored hex dump. This is done to avoid the dependency on the
|
|
most recent mkbootimg tool from AOSP/master. Here is the list of commands which
|
|
was used to generate the boot.img and obtain compressed hex dump from it:
|
|
|
|
$ echo '/dts-v1/; / { model = "x1"; compatible = "y1,z1"; };' > test1.dts
|
|
$ echo '/dts-v1/; / { model = "x2"; compatible = "y2,z2"; };' > test2.dts
|
|
$ dtc test1.dts > dt1.dtb
|
|
$ dtc test2.dts > dt2.dtb
|
|
$ cat dt1.dtb dt2.dtb > dtb.img
|
|
$ echo 'kernel payload' > kernel
|
|
$ echo 'ramdisk payload' > ramdisk.img
|
|
$ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
|
|
--cmdline "cmdline test" --dtb ./dtb.img \
|
|
--os_version R --os_patch_level 2019-06-05 \
|
|
--header_version 2 --output boot.img
|
|
$ gzip -9 boot.img
|
|
$ xxd -p boot.img.gz > boot.img.gz.hex
|
|
|
|
Now one can obtain original boot.img from this hex dump like this:
|
|
|
|
$ xxd -r -p boot.img.gz.hex boot.img.gz
|
|
$ gunzip -9 boot.img.gz
|
|
|
|
For boot image header version 4, these tests rely on two images that are generated
|
|
using the same steps above :
|
|
|
|
1- boot.img :
|
|
$ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
|
|
--cmdline "cmdline test" --dtb ./dtb.img \
|
|
--os_version R --os_patch_level 2019-06-05 \
|
|
--header_version 4 --output ./boot.img
|
|
|
|
2- vendor_boot.img
|
|
$ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
|
|
--cmdline "cmdline test" --dtb ./dtb.img \
|
|
--os_version R --os_patch_level 2019-06-05 \
|
|
--pagesize 4096 --vendor_ramdisk ./ramdisk.img \
|
|
--header_version 4 --vendor_boot ./vboot.img \
|
|
|
|
"""
|
|
|
|
# boot.img.gz hex dump
|
|
img_hex = """1f8b08084844af5d0203626f6f742e696d670073f47309f2f77451e46700
|
|
820606010106301084501f04181819041838181898803c3346060c909c9b
|
|
92939997aa50925a5cc2300a461c3078b2e1793c4b876fd92db97939fb6c
|
|
b7762ffff07d345446c1281805e8a0868d81e117a45e111c0d8dc101b253
|
|
8bf25273140a122b73f21353b8460364148c8251300a46c1281801a02831
|
|
3725b3387bb401300a46c1281805a360148c207081f7df5b20550bc41640
|
|
9c03c41a0c90f17fe85400986d82452b6c3680198a192a0ce17c3610ae34
|
|
d4a9820881a70f3873f35352731892f3730b124b32937252a96bb9119ae5
|
|
463a5546f82c1f05a360148c8251300a462e000085bf67f200200000"""
|
|
|
|
# bootable boot image v4 hex dump (with DTBs)
|
|
boot_img_hex = """1f8b0808e2dd60690203626f6f745f6e65772e696d6700edd8ab0d836018
|
|
40d14f900a0c8c5036e80a24180c24dde04f4034d04740b13d02d90920e7
|
|
8c70e5adbbe6d9b74d5544441987c72dfe64010000009cd5342e9f71beff
|
|
d2367fd3900b0200000017b4a4f7f05a2703000000002e6c0765d9bd6000
|
|
300000"""
|
|
|
|
# bootable vendor boot image v4 hex dump (with DTBs + bootconfig)
|
|
vboot_img_hex = """1f8b0808e2dd6069020376656e646f725f626f6f745f6e65772e696d6700
|
|
eddb316bc24014c0f14b2dd20a425c3b393a48c1d0c1a54be9aca588fbc5
|
|
0b3434e9c979d04628f811fd22426787d2bbc43a68e9d4a5f1ff83f7de25
|
|
5c787053f220d3d1fde3dd783c39174ee86255e68e4f0000e00405e2e835
|
|
e0e142886db9fae8f89c95dbaa7ac5890100f02f1899ab74f1dc9dcb22d3
|
|
52b538110000000000ea67ddfedcb8f2ee6228aa317ecf859fed7fcffefd
|
|
fae68747835d6dec42bc0df6d74d1fc5a0bfac6e89331797b9564926663a
|
|
9f4b9bc659f2b7cda383e6517f19fdd61c0000000080d3111e7c4f030000
|
|
000080fa912fcae854c55adbeb2769d4ab34c9ad4d16963f010000000000
|
|
a88d2fb468951800500000"""
|
|
|
|
# Expected response for "abootimg dtb_dump" command
|
|
dtb_dump_resp="""## DTB area contents (concat format):
|
|
- DTB #0:
|
|
(DTB)size = 125
|
|
(DTB)model = x1
|
|
(DTB)compatible = y1,z1
|
|
- DTB #1:
|
|
(DTB)size = 125
|
|
(DTB)model = x2
|
|
(DTB)compatible = y2,z2"""
|
|
# Address in RAM where to load the boot image ('abootimg' looks in $loadaddr)
|
|
loadaddr = 0x1000
|
|
# Address in RAM where to load the vendor boot image ('abootimg' looks in $vloadaddr)
|
|
vloadaddr= 0x10000
|
|
# Expected DTB #1 size
|
|
dtb1_size = 0x7d
|
|
# Expected DTB #2 size
|
|
dtb2_size = 0x7d
|
|
# Expected DTB #1 offset from the boot image start address
|
|
dtb1_offset = 0x1800 + dtb1_size
|
|
# Expected DTB offset from the vendor boot image start address
|
|
dtb2_offset = 0x2000 + dtb2_size
|
|
# Expected DTB aligned offset
|
|
dtba_offset = 0x4000
|
|
# DTB #1 start address in RAM
|
|
dtb1_addr = loadaddr + dtb1_offset
|
|
# DTB #2 start address in RAM
|
|
dtb2_addr = vloadaddr + dtb2_offset
|
|
|
|
class AbootimgTestDiskImage(object):
|
|
"""Disk image used by abootimg tests."""
|
|
|
|
def __init__(self, ubman, image_name, hex_img):
|
|
"""Initialize a new AbootimgDiskImage object.
|
|
|
|
Args:
|
|
ubman: A U-Boot console.
|
|
|
|
Returns:
|
|
Nothing.
|
|
"""
|
|
|
|
gz_hex = ubman.config.persistent_data_dir + '/' + image_name + '.gz.hex'
|
|
gz = ubman.config.persistent_data_dir + '/' + image_name + '.gz'
|
|
|
|
filename = image_name
|
|
persistent = ubman.config.persistent_data_dir + '/' + filename
|
|
self.path = ubman.config.result_dir + '/' + filename
|
|
ubman.log.action('persistent is ' + persistent)
|
|
with utils.persistent_file_helper(ubman.log, persistent):
|
|
if os.path.exists(persistent):
|
|
ubman.log.action('Disk image file ' + persistent +
|
|
' already exists')
|
|
else:
|
|
ubman.log.action('Generating ' + persistent)
|
|
|
|
f = open(gz_hex, "w")
|
|
f.write(hex_img)
|
|
f.close()
|
|
cmd = ('xxd', '-r', '-p', gz_hex, gz)
|
|
utils.run_and_log(ubman, cmd)
|
|
cmd = ('gunzip', '-9', gz)
|
|
utils.run_and_log(ubman, cmd)
|
|
|
|
cmd = ('cp', persistent, self.path)
|
|
utils.run_and_log(ubman, cmd)
|
|
|
|
gtdi1 = None
|
|
@pytest.fixture(scope='function')
|
|
def abootimg_disk_image(ubman):
|
|
"""pytest fixture to provide a AbootimgTestDiskImage object to tests.
|
|
This is function-scoped because it uses ubman, which is also
|
|
function-scoped. However, we don't need to actually do any function-scope
|
|
work, so this simply returns the same object over and over each time."""
|
|
|
|
global gtdi1
|
|
if not gtdi1:
|
|
gtdi1 = AbootimgTestDiskImage(ubman, 'boot.img', img_hex)
|
|
return gtdi1
|
|
|
|
gtdi2 = None
|
|
@pytest.fixture(scope='function')
|
|
def abootimgv4_disk_image_vboot(ubman):
|
|
"""pytest fixture to provide a AbootimgTestDiskImage object to tests.
|
|
This is function-scoped because it uses ubman, which is also
|
|
function-scoped. However, we don't need to actually do any function-scope
|
|
work, so this simply returns the same object over and over each time."""
|
|
|
|
global gtdi2
|
|
if not gtdi2:
|
|
gtdi2 = AbootimgTestDiskImage(ubman, 'vendor_boot.img', vboot_img_hex)
|
|
return gtdi2
|
|
|
|
gtdi3 = None
|
|
@pytest.fixture(scope='function')
|
|
def abootimgv4_disk_image_boot(ubman):
|
|
"""pytest fixture to provide a AbootimgTestDiskImage object to tests.
|
|
This is function-scoped because it uses ubman, which is also
|
|
function-scoped. However, we don't need to actually do any function-scope
|
|
work, so this simply returns the same object over and over each time."""
|
|
|
|
global gtdi3
|
|
if not gtdi3:
|
|
gtdi3 = AbootimgTestDiskImage(ubman, 'bootv4.img', boot_img_hex)
|
|
return gtdi3
|
|
|
|
@pytest.mark.boardspec('sandbox')
|
|
@pytest.mark.buildconfigspec('android_boot_image')
|
|
@pytest.mark.buildconfigspec('cmd_abootimg')
|
|
@pytest.mark.buildconfigspec('cmd_fdt')
|
|
@pytest.mark.requiredtool('xxd')
|
|
@pytest.mark.requiredtool('gunzip')
|
|
def test_abootimg(abootimg_disk_image, ubman):
|
|
"""Test the 'abootimg' command."""
|
|
|
|
ubman.log.action('Loading disk image to RAM...')
|
|
ubman.run_command('setenv loadaddr 0x%x' % (loadaddr))
|
|
ubman.run_command('host load hostfs - 0x%x %s' % (loadaddr,
|
|
abootimg_disk_image.path))
|
|
|
|
ubman.log.action('Testing \'abootimg get ver\'...')
|
|
response = ubman.run_command('abootimg get ver')
|
|
assert response == "2"
|
|
ubman.run_command('abootimg get ver v')
|
|
response = ubman.run_command('env print v')
|
|
assert response == 'v=2'
|
|
|
|
ubman.log.action('Testing \'abootimg get recovery_dtbo\'...')
|
|
response = ubman.run_command('abootimg get recovery_dtbo a')
|
|
assert response == 'Error: recovery_dtbo_size is 0'
|
|
|
|
ubman.log.action('Testing \'abootimg dump dtb\'...')
|
|
response = ubman.run_command('abootimg dump dtb').replace('\r', '')
|
|
assert response == dtb_dump_resp
|
|
|
|
ubman.log.action('Testing \'abootimg get dtb_load_addr\'...')
|
|
ubman.run_command('abootimg get dtb_load_addr a')
|
|
response = ubman.run_command('env print a')
|
|
assert response == 'a=11f00000'
|
|
|
|
ubman.log.action('Testing \'abootimg get dtb --index\'...')
|
|
ubman.run_command('abootimg get dtb --index=1 dtb1_start dtb1_size')
|
|
response = ubman.run_command('env print dtb1_start')
|
|
correct_str = "dtb1_start=%x" % (dtb1_addr)
|
|
assert response == correct_str
|
|
response = ubman.run_command('env print dtb1_size')
|
|
correct_str = "dtb1_size=%x" % (dtb1_size)
|
|
assert response == correct_str
|
|
ubman.run_command('setenv dtbaaddr 0x%x' % (dtba_offset))
|
|
ubman.run_command('cp.b $dtb1_start $dtbaaddr $dtb1_size')
|
|
ubman.run_command('fdt addr $dtbaaddr')
|
|
ubman.run_command('fdt get value v / model')
|
|
response = ubman.run_command('env print v')
|
|
assert response == 'v=x2'
|
|
|
|
@pytest.mark.boardspec('sandbox')
|
|
@pytest.mark.buildconfigspec('android_boot_image')
|
|
@pytest.mark.buildconfigspec('cmd_abootimg')
|
|
@pytest.mark.buildconfigspec('cmd_fdt')
|
|
@pytest.mark.requiredtool('xxd')
|
|
@pytest.mark.requiredtool('gunzip')
|
|
def test_abootimgv4(abootimgv4_disk_image_vboot, abootimgv4_disk_image_boot, ubman):
|
|
"""Test the 'abootimg' command with boot image header v4."""
|
|
|
|
ubman.log.action('Loading disk image to RAM...')
|
|
ubman.run_command('setenv loadaddr 0x%x' % (loadaddr))
|
|
ubman.run_command('setenv vloadaddr 0x%x' % (vloadaddr))
|
|
ubman.run_command('host load hostfs - 0x%x %s' % (vloadaddr,
|
|
abootimgv4_disk_image_vboot.path))
|
|
ubman.run_command('host load hostfs - 0x%x %s' % (loadaddr,
|
|
abootimgv4_disk_image_boot.path))
|
|
ubman.run_command('abootimg addr 0x%x 0x%x' % (loadaddr, vloadaddr))
|
|
ubman.log.action('Testing \'abootimg get ver\'...')
|
|
response = ubman.run_command('abootimg get ver')
|
|
assert response == "4"
|
|
ubman.run_command('abootimg get ver v')
|
|
response = ubman.run_command('env print v')
|
|
assert response == 'v=4'
|
|
|
|
ubman.log.action('Testing \'abootimg get recovery_dtbo\'...')
|
|
response = ubman.run_command('abootimg get recovery_dtbo a')
|
|
assert response == 'Error: header version must be >= 1 and <= 2 to get dtbo'
|
|
|
|
ubman.log.action('Testing \'abootimg get dtb_load_addr\'...')
|
|
ubman.run_command('abootimg get dtb_load_addr a')
|
|
response = ubman.run_command('env print a')
|
|
assert response == 'a=11f00000'
|
|
|
|
ubman.log.action('Testing \'abootimg get dtb --index\'...')
|
|
ubman.run_command('abootimg get dtb --index=1 dtb2_start dtb2_size')
|
|
response = ubman.run_command('env print dtb2_start')
|
|
correct_str = "dtb2_start=%x" % (dtb2_addr)
|
|
assert response == correct_str
|
|
response = ubman.run_command('env print dtb2_size')
|
|
correct_str = "dtb2_size=%x" % (dtb2_size)
|
|
assert response == correct_str
|
|
|
|
ubman.run_command('setenv dtbaaddr 0x%x' % (dtba_offset))
|
|
ubman.run_command('cp.b $dtb2_start $dtbaaddr $dtb2_size')
|
|
ubman.run_command('fdt addr $dtbaaddr')
|
|
ubman.run_command('fdt get value v / model')
|
|
response = ubman.run_command('env print v')
|
|
assert response == 'v=x2'
|
|
|
|
@pytest.mark.boardspec('sandbox')
|
|
@pytest.mark.buildconfigspec('android_boot_image')
|
|
@pytest.mark.buildconfigspec('cmd_abootimg')
|
|
@pytest.mark.requiredtool('xxd')
|
|
@pytest.mark.requiredtool('gunzip')
|
|
def test_abootimg_bootconfig(abootimgv4_disk_image_vboot,
|
|
abootimgv4_disk_image_boot,
|
|
ubman):
|
|
"""Test bootconfig handling with boot image v4.
|
|
|
|
Verifies that androidboot.* parameters from bootargs are appended to the
|
|
bootconfig section in vendor_boot image in memory, and that non-androidboot
|
|
parameters remain in bootargs.
|
|
"""
|
|
|
|
# Setup addresses
|
|
ram_base = utils.find_ram_base(ubman)
|
|
ramdisk_addr_r = ram_base + 0x4000000
|
|
ubman.run_command('setenv ramdisk_addr_r 0x%x' % ramdisk_addr_r)
|
|
ubman.run_command('setenv loadaddr 0x%x' % loadaddr)
|
|
ubman.run_command('setenv vloadaddr 0x%x' % vloadaddr)
|
|
|
|
# Set bootargs with androidboot.* parameters
|
|
ubman.run_command('setenv bootargs "androidboot.serialno=ABC123 androidboot.mode=recovery console=ttyS0"')
|
|
|
|
# Load images
|
|
ubman.run_command('host load hostfs - 0x%x %s' % (vloadaddr,
|
|
abootimgv4_disk_image_vboot.path))
|
|
ubman.run_command('host load hostfs - 0x%x %s' % (loadaddr,
|
|
abootimgv4_disk_image_boot.path))
|
|
ubman.run_command('abootimg addr 0x%x 0x%x' % (loadaddr, vloadaddr))
|
|
|
|
# Extract ramdisk (triggers bootconfig append)
|
|
ubman.run_command('abootimg get ramdisk ramdisk_addr ramdisk_size')
|
|
|
|
# Get ramdisk address
|
|
response = ubman.run_command('env print ramdisk_addr')
|
|
ramdisk_start = int(response.split('=')[1], 16)
|
|
|
|
# Verify androidboot.* parameters were removed from bootargs
|
|
response = ubman.run_command('env print bootargs')
|
|
assert 'androidboot.' not in response
|
|
assert 'console=ttyS0' in response
|
|
|
|
# Get ramdisk size and verify BOOTCONFIG magic at the end
|
|
response = ubman.run_command('env print ramdisk_size')
|
|
ramdisk_size = int(response.split('=')[1], 16)
|
|
|
|
# Dump the end of the ramdisk where BOOTCONFIG trailer should be
|
|
# The trailer is at the end, so dump the last 48 bytes
|
|
response = ubman.run_command('md.b 0x%x 48' % (ramdisk_start + ramdisk_size - 48))
|
|
|
|
# Verify BOOTCONFIG magic is present
|
|
assert 'BOOTCONFIG' in response
|