test_transfer_list.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2024, Arm Limited. All rights reserved.
  4. #
  5. # SPDX-License-Identifier: BSD-3-Clause
  6. #
  7. """Contains unit tests for the types TransferEntry and TransferList."""
  8. import math
  9. import pytest
  10. from tlc.te import TransferEntry
  11. from tlc.tl import TransferList
  12. large_data = 0xDEADBEEF.to_bytes(4, "big")
  13. small_data = 0x1234.to_bytes(3, "big")
  14. test_entries = [
  15. (0, b""),
  16. (1, small_data),
  17. (1, large_data),
  18. (0xFFFFFF, small_data),
  19. (0xFFFFFF, large_data),
  20. ]
  21. @pytest.mark.parametrize(
  22. "size,csum",
  23. [
  24. (-1, None),
  25. (0x18, 0x9E),
  26. (0x1000, 0xA6),
  27. (0x2000, 0x96),
  28. (0x4000, 0x76),
  29. ],
  30. )
  31. def test_make_transfer_list(size, csum):
  32. if size < 8:
  33. with pytest.raises(AssertionError):
  34. tl = TransferList(size)
  35. else:
  36. tl = TransferList(size)
  37. assert tl.signature == 0x4A0FB10B
  38. assert not tl.entries
  39. assert tl.sum_of_bytes() == 0
  40. assert tl.checksum == csum
  41. @pytest.mark.parametrize(("tag_id", "data"), test_entries)
  42. def test_add_transfer_entry(tag_id, data):
  43. tl = TransferList(0x1000)
  44. te = TransferEntry(tag_id, len(data), data)
  45. tl.add_transfer_entry(tag_id, data)
  46. assert te in tl.entries
  47. assert tl.size == TransferList.hdr_size + te.size
  48. @pytest.mark.parametrize(
  49. ("tag_id", "data"),
  50. [
  51. (-1, None), # tag out of range
  52. (1, None), # no data provided
  53. (1, bytes(8000)), # very large data > total size
  54. (0x100000, b"0dd0edfe"), # tag out of range
  55. ],
  56. )
  57. def test_add_out_of_range_transfer_entry(tag_id, data):
  58. tl = TransferList()
  59. with pytest.raises(Exception):
  60. tl.add_transfer_entry(tag_id, data)
  61. @pytest.mark.parametrize(("tag_id", "data"), test_entries)
  62. def test_calculate_te_sum_of_bytes(tag_id, data):
  63. te = TransferEntry(tag_id, len(data), data)
  64. csum = (
  65. sum(data)
  66. + sum(len(data).to_bytes(4, "big"))
  67. + te.hdr_size
  68. + sum(tag_id.to_bytes(4, "big"))
  69. ) % 256
  70. assert te.sum_of_bytes == csum
  71. @pytest.mark.parametrize(("tag_id", "data"), test_entries)
  72. def test_calculate_tl_checksum(tag_id, data):
  73. tl = TransferList(0x1000)
  74. tl.add_transfer_entry(tag_id, data)
  75. assert tl.sum_of_bytes() == 0
  76. def test_empty_transfer_list_blob(tmpdir):
  77. """Check that we can correctly create a transfer list header."""
  78. test_file = tmpdir.join("test_tl_blob.bin")
  79. tl = TransferList()
  80. tl.write_to_file(test_file)
  81. with open(test_file, "rb") as f:
  82. assert f.read(tl.hdr_size) == tl.header_to_bytes()
  83. @pytest.mark.parametrize(("tag_id", "data"), test_entries)
  84. def test_single_te_transfer_list(tag_id, data, tmpdir):
  85. """Check that we can create a complete TL with a single TE."""
  86. test_file = tmpdir.join("test_tl_blob.bin")
  87. tl = TransferList(0x1000)
  88. tl.add_transfer_entry(tag_id, data)
  89. tl.write_to_file(test_file)
  90. te = tl.entries[0]
  91. with open(test_file, "rb") as f:
  92. assert f.read(tl.hdr_size) == tl.header_to_bytes()
  93. assert int.from_bytes(f.read(3), "little") == te.id
  94. assert int.from_bytes(f.read(1), "little") == te.hdr_size
  95. assert int.from_bytes(f.read(4), "little") == te.data_size
  96. assert f.read(te.data_size) == te.data
  97. def test_multiple_te_transfer_list(tmpdir):
  98. """Check that we can create a TL with multiple TE's."""
  99. test_file = tmpdir.join("test_tl_blob.bin")
  100. tl = TransferList(0x1000)
  101. for tag_id, data in test_entries:
  102. tl.add_transfer_entry(tag_id, data)
  103. tl.write_to_file(test_file)
  104. with open(test_file, "rb") as f:
  105. assert f.read(tl.hdr_size) == tl.header_to_bytes()
  106. # Ensure that TE's have the correct alignment
  107. for tag_id, data in test_entries:
  108. f.seek(int(math.ceil(f.tell() / 2**tl.alignment) * 2**tl.alignment))
  109. print(f.tell())
  110. assert int.from_bytes(f.read(3), "little") == tag_id
  111. assert int.from_bytes(f.read(1), "little") == TransferEntry.hdr_size
  112. # Make sure the data in the TE matches the data in the original case
  113. data_size = int.from_bytes(f.read(4), "little")
  114. assert f.read(data_size) == data
  115. def test_read_empty_transfer_list_from_file(tmpdir):
  116. test_file = tmpdir.join("test_tl_blob.bin")
  117. original_tl = TransferList(0x1000)
  118. original_tl.write_to_file(test_file)
  119. # Read the contents of the file we just wrote
  120. tl = TransferList.fromfile(test_file)
  121. assert tl.header_to_bytes() == original_tl.header_to_bytes()
  122. assert tl.sum_of_bytes() == 0
  123. def test_read_single_transfer_list_from_file(tmpdir):
  124. test_file = tmpdir.join("test_tl_blob.bin")
  125. original_tl = TransferList(0x1000)
  126. original_tl.add_transfer_entry(test_entries[0][0], test_entries[0][1])
  127. original_tl.write_to_file(test_file)
  128. # Read the contents of the file we just wrote
  129. tl = TransferList.fromfile(test_file)
  130. assert tl.entries
  131. te = tl.entries[0]
  132. assert te.id == test_entries[0][0]
  133. assert te.data == test_entries[0][1]
  134. assert tl.sum_of_bytes() == 0
  135. def test_read_multiple_transfer_list_from_file(tmpdir):
  136. test_file = tmpdir.join("test_tl_blob.bin")
  137. original_tl = TransferList(0x1000)
  138. for tag_id, data in test_entries:
  139. original_tl.add_transfer_entry(tag_id, data)
  140. original_tl.write_to_file(test_file)
  141. # Read the contents of the file we just wrote
  142. tl = TransferList.fromfile(test_file)
  143. # The TE we derive from the file might have a an associated offset, compare
  144. # the TE's based on the header in bytes, which doesn't account for this.
  145. for te0, te1 in zip(tl.entries, original_tl.entries):
  146. assert te0.header_to_bytes() == te1.header_to_bytes()
  147. assert tl.sum_of_bytes() == 0
  148. @pytest.mark.parametrize("tag", [tag for tag, _ in test_entries])
  149. def test_remove_tag_from_file(tag):
  150. tl = TransferList(0x1000)
  151. for tag_id, data in test_entries:
  152. tl.add_transfer_entry(tag_id, data)
  153. removed_entries = list(filter(lambda te: te.id == tag, tl.entries))
  154. original_size = tl.size
  155. tl.remove_tag(tag)
  156. assert not any(tag == te.id for te in tl.entries)
  157. assert tl.size == original_size - sum(map(lambda te: te.size, removed_entries))
  158. def test_get_fdt_offset(tmpdir):
  159. tl = TransferList(0x1000)
  160. tl.add_transfer_entry(1, 0xEDFE0DD0.to_bytes(4, "big"))
  161. f = tmpdir.join("blob.bin")
  162. tl.write_to_file(f)
  163. blob_tl = TransferList.fromfile(f)
  164. assert blob_tl.hdr_size + TransferEntry.hdr_size == blob_tl.get_entry_data_offset(1)
  165. def test_get_missing_fdt_offset(tmpdir):
  166. tl = TransferList(0x1000)
  167. f = tmpdir.join("blob.bin")
  168. tl.write_to_file(f)
  169. blob_tl = TransferList.fromfile(f)
  170. with pytest.raises(ValueError):
  171. blob_tl.get_entry_data_offset(1)