fdt_test.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. #!/usr/bin/python
  2. # This file is part of the flashrom project.
  3. #
  4. # Copyright (C) 2013 Google Inc.
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; version 2 of the License.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. import binascii
  19. import os
  20. import struct
  21. import unittest
  22. # Use this to find the FDT containing the flashmap
  23. FDTMAP_SIGNATURE = '__FDTM__'
  24. fdt_src = """
  25. /dts-v1/;
  26. / {
  27. #address-cells = <0x00000001>;
  28. #size-cells = <0x00000001>;
  29. model = "NVIDIA Seaboard";
  30. compatible = "nvidia,seaboard", "nvidia,tegra250";
  31. interrupt-parent = <0x00000001>;
  32. flash@0 {
  33. #address-cells = <0x00000001>;
  34. #size-cells = <0x00000001>;
  35. compatible = "winbond,W25Q32BVSSIG", "cfi-flash", "chromeos,flashmap";
  36. reg = <0x00000000 0x00400000>;
  37. onestop-layout@0 {
  38. label = "onestop-layout";
  39. reg = <0x00000000 0x00080000>;
  40. };
  41. firmware-image@0 {
  42. label = "firmware-image";
  43. reg = <0x00000000 0x0007df00>;
  44. };
  45. verification-block@7df00 {
  46. label = "verification-block";
  47. reg = <0x0007df00 0x00002000>;
  48. };
  49. firmware-id@7ff00 {
  50. label = "firmware-id";
  51. reg = <0x0007ff00 0x00000100>;
  52. };
  53. readonly@0 {
  54. label = "readonly";
  55. reg = <0x00000000 0x00100000>;
  56. read-only;
  57. };
  58. bct@0 {
  59. label = "bct";
  60. reg = <0x00000000 0x00010000>;
  61. read-only;
  62. };
  63. ro-onestop@10000 {
  64. label = "ro-onestop";
  65. reg = <%(start)#x %(size)#x>;
  66. read-only;
  67. type = "blob boot";
  68. };
  69. ro-gbb@90000 {
  70. label = "gbb";
  71. reg = <0x00090000 0x00020000>;
  72. read-only;
  73. type = "blob gbb";
  74. };
  75. ro-data@b0000 {
  76. label = "ro-data";
  77. reg = <0x000b0000 0x00010000>;
  78. read-only;
  79. };
  80. ro-vpd@c0000 {
  81. label = "ro-vpd";
  82. reg = <0x000c0000 0x00008000>;
  83. read-only;
  84. type = "wiped";
  85. wipe-value = [ffffffff];
  86. };
  87. fdtmap {
  88. label = "ro-fdtmap";
  89. reg = <%(fdtmap_pos)#x %(fdtmap_size)#x>;
  90. read-only;
  91. type = "fdtmap";
  92. };
  93. fmap {
  94. label = "ro-fmap";
  95. reg = <0x000d0000 0x00000400>;
  96. read-only;
  97. type = "fmap";
  98. ver-major = <0x00000001>;
  99. ver-minor = <0x00000000>;
  100. };
  101. readwrite@100000 {
  102. label = "readwrite";
  103. reg = <0x00100000 0x00100000>;
  104. };
  105. rw-vpd@100000 {
  106. label = "rw-vpd";
  107. reg = <0x00100000 0x00080000>;
  108. type = "wiped";
  109. wipe-value = [ffffffff];
  110. };
  111. shared-dev-cfg@180000 {
  112. victoria;
  113. label = "shared-dev-cfg";
  114. reg = <0x00180000 0x00040000>;
  115. type = "wiped";
  116. wipe-value = "";
  117. };
  118. shared-data@1c0000 {
  119. label = "shared-data";
  120. reg = <0x001c0000 0x00030000>;
  121. type = "wiped";
  122. wipe-value = "";
  123. };
  124. shared-env@1ff000 {
  125. label = "shared-env";
  126. reg = <0x001ff000 0x00001000>;
  127. type = "wiped";
  128. wipe-value = "";
  129. };
  130. readwrite-a@200000 {
  131. label = "readwrite-a";
  132. reg = <0x00200000 0x00080000>;
  133. block-lba = <0x00000022>;
  134. };
  135. rw-a-onestop@200000 {
  136. label = "rw-a-onestop";
  137. reg = <0x00200000 0x00080000>;
  138. type = "blob boot";
  139. };
  140. readwrite-b@300000 {
  141. label = "readwrite-b";
  142. reg = <0x00300000 0x00080000>;
  143. block-lba = <0x00000422>;
  144. };
  145. rw-b-onestop@300000 {
  146. label = "rw-b-onestop";
  147. reg = <%(rw_start)#x %(rw_size)#x>;
  148. type = "blob boot";
  149. };
  150. };
  151. config {
  152. silent_console = <0x00000000>;
  153. odmdata = <0x300d8011>;
  154. hwid = "ARM SEABOARD TEST 1176";
  155. machine-arch-id = <0x00000bbd>;
  156. gpio_port_write_protect_switch = <0x0000003b>;
  157. gpio_port_recovery_switch = <0x00000038>;
  158. gpio_port_developer_switch = <0x000000a8>;
  159. polarity_write_protect_switch = <0x00000001>;
  160. polarity_recovery_switch = <0x00000000>;
  161. polarity_developer_switch = <0x00000001>;
  162. };
  163. };
  164. """
  165. flash_size = 4 * 1024 * 1024
  166. fdtmap_size = 0x00008000
  167. src_fname = 'test.dts'
  168. dtb_fname = 'test.dtb'
  169. image_fname = 'image.bin'
  170. part_fname = 'part.bin'
  171. start = 0x10000
  172. size = 0x80000
  173. rw_start = 0x380000
  174. rw_size = 0x8000
  175. def Run(args):
  176. """Run a command + args and raise if it fails.
  177. Args:
  178. args: List of arguments, first is the program to run.
  179. Raises:
  180. OSError: Raised if the command fails.
  181. """
  182. cmd = ' '.join(args)
  183. print cmd
  184. if os.system(cmd):
  185. raise OSError("Command '%s' failed" % cmd)
  186. class TestFlashrom(unittest.TestCase):
  187. """Unit test class for flashrom."""
  188. def setUp(self):
  189. """Set up read to run some tests.
  190. Create a chunk of data to be written to the image, in self.part.
  191. """
  192. # Create some dummy data.
  193. part = ''
  194. for i in range(size):
  195. part += '%d.' % i
  196. if len(part) > size:
  197. break
  198. self.part = part[:size]
  199. self.rw_part = part[1:rw_size + 1]
  200. part_image = chr(0xff) * flash_size
  201. part_image = self.InsertData(part_image, start, self.part)
  202. part_image = self.InsertData(part_image, rw_start, self.rw_part)
  203. open(part_fname, 'wb').write(part_image)
  204. def InsertData(self, image, pos, data):
  205. """Insert some data into an image.
  206. Args:
  207. image: String containing input image.
  208. pos: Position to place data.
  209. data: Data to place (a string).
  210. Returns:
  211. String containing updated image.
  212. """
  213. return image[:pos] + data + image[pos + len(data):]
  214. def GetHeader(self, sig, data, bad_crc=False):
  215. """Create a suitable header for an FDTMAP.
  216. Args:
  217. sig: Sigature to use (string).
  218. data: Data to write (only the length is used here).
  219. bad_crc: True to force the header to have a bad CRC.
  220. Returns:
  221. FDTMAP header for the given data.
  222. """
  223. crc32 = binascii.crc32(data) & 0xffffffff
  224. if bad_crc:
  225. crc32 += 1
  226. return struct.pack('<8sLL', sig, len(data), crc32)
  227. def TryTest(self, sig=FDTMAP_SIGNATURE, fdtmap_pos=0x000c8000,
  228. bad_crc=False, bad_size=False, decoy=False,
  229. alt_region=False):
  230. """Simple test to check that an FDT flashmap works correctly.
  231. Create an FDT map and write it to an image file. Then write a single
  232. part of that image, read it back and return it. This allows the caller
  233. to verify that the FDT map functionality works.
  234. Args:
  235. sig: Sigature to use (string).
  236. fdtmap_pos: Position in image where FDTMAP will go.
  237. bad_crc: True to force the header to have a bad CRC.
  238. bad_size: True to force the size field to be incorrect.
  239. decoy: True to create lots of decoy blocks with invalid signatures or
  240. CRCs.
  241. alt_region: True to use the alternative RW region for the test
  242. Returns:
  243. Contents of the part that was read back from the created image.
  244. """
  245. # Create the FDT source file, then compile it.
  246. props = {
  247. 'start': start,
  248. 'size': size,
  249. 'fdtmap_pos': fdtmap_pos,
  250. 'fdtmap_size': fdtmap_size,
  251. 'rw_start' : rw_start,
  252. 'rw_size' : rw_size,
  253. }
  254. with open(src_fname, 'w') as fd:
  255. print >>fd, fdt_src % props
  256. Run(['dtc', '-O', 'dtb', '-o', dtb_fname, src_fname])
  257. # Create an image and put the flashmap in it.
  258. image = chr(0) * flash_size
  259. with open(dtb_fname, 'r') as fd:
  260. data = fd.read()
  261. if bad_size:
  262. data = data[4:]
  263. fdtmap = self.GetHeader(sig, data, bad_crc)
  264. if decoy:
  265. for upto in range(0, flash_size, 0x20000):
  266. image = self.InsertData(image, upto, fdtmap + data[:-4] + 'junk')
  267. bad_data = self.GetHeader(sig, data[0x100:], True) + data[0x100:]
  268. image = self.InsertData(image, upto + 0x10000, bad_data)
  269. image = self.InsertData(image, fdtmap_pos, fdtmap + data)
  270. with open(image_fname, 'wb') as fd:
  271. fd.write(image)
  272. # Use flashrom to write it into the image.
  273. if alt_region:
  274. region = 'RW_B_ONESTOP'
  275. else:
  276. region = 'RO_ONESTOP'
  277. args = ['sudo', '../flashrom',
  278. '-p', 'dummy:emulate=SST25VF032B,image=%s' % image_fname,
  279. '-w', part_fname, '-i', region]
  280. Run(args)
  281. # Read it back.
  282. os.unlink(part_fname)
  283. args[4] = '-r'
  284. Run(args)
  285. # Make sure that it matches.
  286. with open(part_fname, 'rb') as fd:
  287. check = fd.read()
  288. if alt_region:
  289. check = check[rw_start:rw_start + rw_size]
  290. else:
  291. check = check[start:start + size]
  292. Run(['sudo', 'rm', '-f', part_fname])
  293. return check
  294. def checkData(self, part, result):
  295. if part != result:
  296. print 'Part size %d: %s' % (len(self.rw_part), self.rw_part[:100])
  297. print 'Result size %d: %s' % (len(result), result[:100])
  298. self.fail('Failed to find correct data at expected location')
  299. def testValidmap(self):
  300. """Simple test with fairly well aligned fdtmap."""
  301. self.checkData(self.part, self.TryTest())
  302. def testExhaustiveSearch(self):
  303. """Test that the exhaustive search works OK."""
  304. self.checkData(self.part, self.TryTest(fdtmap_pos=0x000c8001))
  305. def testInvalidSignature(self):
  306. """Make sure that a bad signature is detected."""
  307. self.assertRaises(OSError, self.TryTest, sig='bad sig!')
  308. def testInvalidCRC(self):
  309. """Make sure that an invalid CRC32 is detected."""
  310. self.assertRaises(OSError, self.TryTest, bad_crc=True)
  311. def testInvalidSize(self):
  312. """Make sure that an invalid FDT size is detected."""
  313. self.assertRaises(OSError, self.TryTest, bad_size=True)
  314. def testDecoy(self):
  315. """Make sure that decoys (bad FDT maps) don't throw us off."""
  316. self.checkData(self.part, self.TryTest(decoy=True))
  317. def testLastRegion(self):
  318. """Make sure that the entire FDTMAP is read correctly."""
  319. self.checkData(self.rw_part, self.TryTest(alt_region=True))
  320. if __name__ == '__main__':
  321. print 'Testing fdtmap'
  322. unittest.main()