test_abootimg.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. # SPDX-License-Identifier: GPL-2.0+
  2. # Copyright (c) 2020
  3. # Author: Sam Protsenko <joe.skb7@gmail.com>
  4. # Test U-Boot's "abootimg" commands.
  5. import os
  6. import pytest
  7. import u_boot_utils
  8. """
  9. These tests rely on disk image (boot.img), which is automatically created by
  10. the test from the stored hex dump. This is done to avoid the dependency on the
  11. most recent mkbootimg tool from AOSP/master. Here is the list of commands which
  12. was used to generate the boot.img and obtain compressed hex dump from it:
  13. $ echo '/dts-v1/; / { model = "x1"; compatible = "y1,z1"; };' > test1.dts
  14. $ echo '/dts-v1/; / { model = "x2"; compatible = "y2,z2"; };' > test2.dts
  15. $ dtc test1.dts > dt1.dtb
  16. $ dtc test2.dts > dt2.dtb
  17. $ cat dt1.dtb dt2.dtb > dtb.img
  18. $ echo 'kernel payload' > kernel
  19. $ echo 'ramdisk payload' > ramdisk.img
  20. $ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
  21. --cmdline "cmdline test" --dtb ./dtb.img \
  22. --os_version R --os_patch_level 2019-06-05 \
  23. --header_version 2 --output boot.img
  24. $ gzip -9 boot.img
  25. $ xxd -p boot.img.gz > boot.img.gz.hex
  26. Now one can obtain original boot.img from this hex dump like this:
  27. $ xxd -r -p boot.img.gz.hex boot.img.gz
  28. $ gunzip -9 boot.img.gz
  29. For boot image header version 4, these tests rely on two images that are generated
  30. using the same steps above :
  31. 1- boot.img :
  32. $ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
  33. --cmdline "cmdline test" --dtb ./dtb.img \
  34. --os_version R --os_patch_level 2019-06-05 \
  35. --header_version 4 --output ./boot.img
  36. 2- vendor_boot.img
  37. $ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
  38. --cmdline "cmdline test" --dtb ./dtb.img \
  39. --os_version R --os_patch_level 2019-06-05 \
  40. --pagesize 4096 --vendor_ramdisk ./ramdisk.img \
  41. --header_version 4 --vendor_boot ./vboot.img \
  42. """
  43. # boot.img.gz hex dump
  44. img_hex = """1f8b08084844af5d0203626f6f742e696d670073f47309f2f77451e46700
  45. 820606010106301084501f04181819041838181898803c3346060c909c9b
  46. 92939997aa50925a5cc2300a461c3078b2e1793c4b876fd92db97939fb6c
  47. b7762ffff07d345446c1281805e8a0868d81e117a45e111c0d8dc101b253
  48. 8bf25273140a122b73f21353b8460364148c8251300a46c1281801a02831
  49. 3725b3387bb401300a46c1281805a360148c207081f7df5b20550bc41640
  50. 9c03c41a0c90f17fe85400986d82452b6c3680198a192a0ce17c3610ae34
  51. d4a9820881a70f3873f35352731892f3730b124b32937252a96bb9119ae5
  52. 463a5546f82c1f05a360148c8251300a462e000085bf67f200200000"""
  53. # boot img v4 hex dump
  54. boot_img_hex = """1f8b080827b0cd630203626f6f742e696d6700edd8bd0d82601885d1d7c4
  55. 58d8c808b88195bd098d8d246e40e42b083f1aa0717be99d003d277916b8
  56. e5bddc8a7b792d8e8788c896ce9b88d32ebe6c971e7ddd3543cae734cd01
  57. c0ffc84c0000b0766d1a87d4e5afeadd3dab7a6f10000000f84163d5d7cd
  58. d43a000000000000000060c53e7544995700400000"""
  59. # vendor boot image v4 hex dump
  60. vboot_img_hex = """1f8b0808baaecd63020376626f6f742e696d6700edd8310b824018c6f1b3
  61. 222a08f41b3436b4280dcdd19c11d16ee9109d18d59042d047ec8b04cd0d
  62. d19d5a4345534bf6ffc173ef29272f38e93b1d0ec67dd79d548462aa1cd2
  63. d5d20b0000f8438678f90c18d584b8a4bbb3a557991ecb2a0000f80d6b2f
  64. f4179b656be5c532f2fc066f040000000080e23936af2755f62a3d918df1
  65. db2a7ab67f9ffdeb7df7cda3465ecb79c4ce7e5c577562bb9364b74449a5
  66. 1e467e20c53c0a57de763193c1779b3b4fcd9d4ee27c6a0e00000000c0ff
  67. 309ffea7010000000040f1dc004129855400400000"""
  68. # Expected response for "abootimg dtb_dump" command
  69. dtb_dump_resp="""## DTB area contents (concat format):
  70. - DTB #0:
  71. (DTB)size = 125
  72. (DTB)model = x1
  73. (DTB)compatible = y1,z1
  74. - DTB #1:
  75. (DTB)size = 125
  76. (DTB)model = x2
  77. (DTB)compatible = y2,z2"""
  78. # Address in RAM where to load the boot image ('abootimg' looks in $loadaddr)
  79. loadaddr = 0x1000
  80. # Address in RAM where to load the vendor boot image ('abootimg' looks in $vloadaddr)
  81. vloadaddr= 0x10000
  82. # Expected DTB #1 offset from the boot image start address
  83. dtb1_offset = 0x187d
  84. # Expected DTB offset from the vendor boot image start address
  85. dtb2_offset = 0x207d
  86. # DTB #1 start address in RAM
  87. dtb1_addr = loadaddr + dtb1_offset
  88. # DTB #2 start address in RAM
  89. dtb2_addr = vloadaddr + dtb2_offset
  90. class AbootimgTestDiskImage(object):
  91. """Disk image used by abootimg tests."""
  92. def __init__(self, u_boot_console, image_name, hex_img):
  93. """Initialize a new AbootimgDiskImage object.
  94. Args:
  95. u_boot_console: A U-Boot console.
  96. Returns:
  97. Nothing.
  98. """
  99. gz_hex = u_boot_console.config.persistent_data_dir + '/' + image_name + '.gz.hex'
  100. gz = u_boot_console.config.persistent_data_dir + '/' + image_name + '.gz'
  101. filename = image_name
  102. persistent = u_boot_console.config.persistent_data_dir + '/' + filename
  103. self.path = u_boot_console.config.result_dir + '/' + filename
  104. u_boot_console.log.action('persistent is ' + persistent)
  105. with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent):
  106. if os.path.exists(persistent):
  107. u_boot_console.log.action('Disk image file ' + persistent +
  108. ' already exists')
  109. else:
  110. u_boot_console.log.action('Generating ' + persistent)
  111. f = open(gz_hex, "w")
  112. f.write(hex_img)
  113. f.close()
  114. cmd = ('xxd', '-r', '-p', gz_hex, gz)
  115. u_boot_utils.run_and_log(u_boot_console, cmd)
  116. cmd = ('gunzip', '-9', gz)
  117. u_boot_utils.run_and_log(u_boot_console, cmd)
  118. cmd = ('cp', persistent, self.path)
  119. u_boot_utils.run_and_log(u_boot_console, cmd)
  120. gtdi1 = None
  121. @pytest.fixture(scope='function')
  122. def abootimg_disk_image(u_boot_console):
  123. """pytest fixture to provide a AbootimgTestDiskImage object to tests.
  124. This is function-scoped because it uses u_boot_console, which is also
  125. function-scoped. However, we don't need to actually do any function-scope
  126. work, so this simply returns the same object over and over each time."""
  127. global gtdi1
  128. if not gtdi1:
  129. gtdi1 = AbootimgTestDiskImage(u_boot_console, 'boot.img', img_hex)
  130. return gtdi1
  131. gtdi2 = None
  132. @pytest.fixture(scope='function')
  133. def abootimgv4_disk_image_vboot(u_boot_console):
  134. """pytest fixture to provide a AbootimgTestDiskImage object to tests.
  135. This is function-scoped because it uses u_boot_console, which is also
  136. function-scoped. However, we don't need to actually do any function-scope
  137. work, so this simply returns the same object over and over each time."""
  138. global gtdi2
  139. if not gtdi2:
  140. gtdi2 = AbootimgTestDiskImage(u_boot_console, 'vendor_boot.img', vboot_img_hex)
  141. return gtdi2
  142. gtdi3 = None
  143. @pytest.fixture(scope='function')
  144. def abootimgv4_disk_image_boot(u_boot_console):
  145. """pytest fixture to provide a AbootimgTestDiskImage object to tests.
  146. This is function-scoped because it uses u_boot_console, which is also
  147. function-scoped. However, we don't need to actually do any function-scope
  148. work, so this simply returns the same object over and over each time."""
  149. global gtdi3
  150. if not gtdi3:
  151. gtdi3 = AbootimgTestDiskImage(u_boot_console, 'bootv4.img', boot_img_hex)
  152. return gtdi3
  153. @pytest.mark.boardspec('sandbox')
  154. @pytest.mark.buildconfigspec('android_boot_image')
  155. @pytest.mark.buildconfigspec('cmd_abootimg')
  156. @pytest.mark.buildconfigspec('cmd_fdt')
  157. @pytest.mark.requiredtool('xxd')
  158. @pytest.mark.requiredtool('gunzip')
  159. def test_abootimg(abootimg_disk_image, u_boot_console):
  160. """Test the 'abootimg' command."""
  161. u_boot_console.log.action('Loading disk image to RAM...')
  162. u_boot_console.run_command('setenv loadaddr 0x%x' % (loadaddr))
  163. u_boot_console.run_command('host load hostfs - 0x%x %s' % (loadaddr,
  164. abootimg_disk_image.path))
  165. u_boot_console.log.action('Testing \'abootimg get ver\'...')
  166. response = u_boot_console.run_command('abootimg get ver')
  167. assert response == "2"
  168. u_boot_console.run_command('abootimg get ver v')
  169. response = u_boot_console.run_command('env print v')
  170. assert response == 'v=2'
  171. u_boot_console.log.action('Testing \'abootimg get recovery_dtbo\'...')
  172. response = u_boot_console.run_command('abootimg get recovery_dtbo a')
  173. assert response == 'Error: recovery_dtbo_size is 0'
  174. u_boot_console.log.action('Testing \'abootimg dump dtb\'...')
  175. response = u_boot_console.run_command('abootimg dump dtb').replace('\r', '')
  176. assert response == dtb_dump_resp
  177. u_boot_console.log.action('Testing \'abootimg get dtb_load_addr\'...')
  178. u_boot_console.run_command('abootimg get dtb_load_addr a')
  179. response = u_boot_console.run_command('env print a')
  180. assert response == 'a=11f00000'
  181. u_boot_console.log.action('Testing \'abootimg get dtb --index\'...')
  182. u_boot_console.run_command('abootimg get dtb --index=1 dtb1_start')
  183. response = u_boot_console.run_command('env print dtb1_start')
  184. correct_str = "dtb1_start=%x" % (dtb1_addr)
  185. assert response == correct_str
  186. u_boot_console.run_command('fdt addr $dtb1_start')
  187. u_boot_console.run_command('fdt get value v / model')
  188. response = u_boot_console.run_command('env print v')
  189. assert response == 'v=x2'
  190. @pytest.mark.boardspec('sandbox')
  191. @pytest.mark.buildconfigspec('android_boot_image')
  192. @pytest.mark.buildconfigspec('cmd_abootimg')
  193. @pytest.mark.buildconfigspec('cmd_fdt')
  194. @pytest.mark.requiredtool('xxd')
  195. @pytest.mark.requiredtool('gunzip')
  196. def test_abootimgv4(abootimgv4_disk_image_vboot, abootimgv4_disk_image_boot, u_boot_console):
  197. """Test the 'abootimg' command with boot image header v4."""
  198. cons = u_boot_console
  199. cons.log.action('Loading disk image to RAM...')
  200. cons.run_command('setenv loadaddr 0x%x' % (loadaddr))
  201. cons.run_command('setenv vloadaddr 0x%x' % (vloadaddr))
  202. cons.run_command('host load hostfs - 0x%x %s' % (vloadaddr,
  203. abootimgv4_disk_image_vboot.path))
  204. cons.run_command('host load hostfs - 0x%x %s' % (loadaddr,
  205. abootimgv4_disk_image_boot.path))
  206. cons.run_command('abootimg addr 0x%x 0x%x' % (loadaddr, vloadaddr))
  207. cons.log.action('Testing \'abootimg get ver\'...')
  208. response = cons.run_command('abootimg get ver')
  209. assert response == "4"
  210. cons.run_command('abootimg get ver v')
  211. response = cons.run_command('env print v')
  212. assert response == 'v=4'
  213. cons.log.action('Testing \'abootimg get recovery_dtbo\'...')
  214. response = cons.run_command('abootimg get recovery_dtbo a')
  215. assert response == 'Error: header version must be >= 1 and <= 2 to get dtbo'
  216. cons.log.action('Testing \'abootimg get dtb_load_addr\'...')
  217. cons.run_command('abootimg get dtb_load_addr a')
  218. response = cons.run_command('env print a')
  219. assert response == 'a=11f00000'
  220. cons.log.action('Testing \'abootimg get dtb --index\'...')
  221. cons.run_command('abootimg get dtb --index=1 dtb2_start')
  222. response = cons.run_command('env print dtb2_start')
  223. correct_str = "dtb2_start=%x" % (dtb2_addr)
  224. assert response == correct_str
  225. cons.run_command('fdt addr $dtb2_start')
  226. cons.run_command('fdt get value v / model')
  227. response = cons.run_command('env print v')
  228. assert response == 'v=x2'