pylibfdt: Support the sequential-write interface

It is useful to be able to create a device tree from scratch using
software. This is supported in libfdt but not currently available in the
Python bindings.

Add a new FdtSw class to handle this, with various methods corresponding
to the libfdt functions. When the tree is complete, calling AsFdt() will
return the completed device-tree object.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Simon Glass 2018-07-10 14:49:07 -06:00 committed by David Gibson
parent 9b0e4fe260
commit 853649acce
2 changed files with 497 additions and 82 deletions

View file

@ -56,17 +56,32 @@ import unittest
sys.path.insert(0, '../pylibfdt')
import libfdt
from libfdt import Fdt, FdtException, QUIET_NOTFOUND, QUIET_ALL
from libfdt import Fdt, FdtSw, FdtException, QUIET_NOTFOUND, QUIET_ALL
small_size = 160
full_size = 1024
TEST_ADDR_1H = 0xdeadbeef
TEST_ADDR_1L = 0x00000000
TEST_ADDR_1 = (TEST_ADDR_1H << 32) | TEST_ADDR_1L
TEST_ADDR_1 = 0x8000000000000000
TEST_SIZE_1H = 0x00000000
TEST_SIZE_1L = 0x00100000
TEST_SIZE_1 = (TEST_SIZE_1H << 32) | TEST_SIZE_1L
TEST_ADDR_2H = 0
TEST_ADDR_2L = 123456789
TEST_ADDR_2 = (TEST_ADDR_2H << 32) | TEST_ADDR_2L
TEST_SIZE_2H = 0
TEST_SIZE_2L = 010000
TEST_SIZE_2 = (TEST_SIZE_2H << 32) | TEST_SIZE_2L
TEST_VALUE_1 = 0xdeadbeef
TEST_VALUE_2 = 123456789
TEST_VALUE64_1H = 0xdeadbeef
TEST_VALUE64_1L = 0x01abcdef
TEST_VALUE64_1 = (TEST_VALUE64_1H << 32) | TEST_VALUE64_1L
PHANDLE_1 = 0x2000
PHANDLE_2 = 0x2001
TEST_STRING_1 = 'hello world'
TEST_STRING_2 = 'hi world'
TEST_STRING_3 = u'unicode ' + unichr(467)
@ -94,8 +109,8 @@ def _ReadFdt(fname):
"""
return libfdt.Fdt(open(fname).read())
class PyLibfdtTests(unittest.TestCase):
"""Test class for pylibfdt
class PyLibfdtBasicTests(unittest.TestCase):
"""Test class for basic pylibfdt access functions
Properties:
fdt: Device tree file used for testing
@ -481,5 +496,99 @@ class PyLibfdtTests(unittest.TestCase):
self.assertIn('embedded nul', str(e.exception))
class PyLibfdtSwTests(unittest.TestCase):
"""Test class for pylibfdt sequential-write DT creation
"""
def assertOk(self, err_code):
self.assertEquals(0, err_code)
def testCreate(self):
# First check the minimum size and also the FdtSw() constructor
with self.assertRaisesRegexp(FdtException, get_err(libfdt.NOSPACE)):
self.assertEquals(-libfdt.NOSPACE, FdtSw(3))
sw = FdtSw()
sw.add_reservemap_entry(TEST_ADDR_1, TEST_SIZE_1)
sw.add_reservemap_entry(TEST_ADDR_2, TEST_SIZE_2)
sw.finish_reservemap()
sw.begin_node('')
sw.property_string('compatible', 'test_tree1')
sw.property_u32('prop-int', TEST_VALUE_1)
sw.property_u32('prop-int', TEST_VALUE_1)
sw.property_u64('prop-int64', TEST_VALUE64_1)
sw.property_string('prop-str', TEST_STRING_1)
sw.property_u32('#address-cells', 1)
sw.property_u32('#size-cells', 0)
sw.begin_node('subnode@1')
sw.property_string('compatible', 'subnode1')
sw.property_u32('reg', 1)
sw.property_cell('prop-int', TEST_VALUE_1)
sw.begin_node('subsubnode')
sw.property('compatible', 'subsubnode1\0subsubnode')
sw.property_cell('prop-int', TEST_VALUE_1)
sw.end_node()
sw.begin_node('ss1')
sw.end_node()
sw.end_node()
for i in range(2, 11):
with sw.add_node('subnode@%d' % i):
sw.property_u32('reg', 2)
sw.property_cell('linux,phandle', PHANDLE_1)
sw.property_cell('prop-int', TEST_VALUE_2)
sw.property_u32('#address-cells', 1)
sw.property_u32('#size-cells', 0)
with sw.add_node('subsubnode@0'):
sw.property_u32('reg', 0)
sw.property_cell('phandle', PHANDLE_2)
sw.property('compatible', 'subsubnode2\0subsubnode')
sw.property_cell('prop-int', TEST_VALUE_2)
with sw.add_node('ss2'):
pass
sw.end_node()
fdt = sw.as_fdt()
self.assertEqual(2, fdt.num_mem_rsv())
self.assertEqual([TEST_ADDR_1, TEST_SIZE_1], fdt.get_mem_rsv(0))
# Make sure we can add a few more things
with sw.add_node('another'):
sw.property_u32('reg', 3)
# Make sure we can read from the tree too
node = sw.path_offset('/subnode@1')
self.assertEqual('subnode1' + chr(0), sw.getprop(node, 'compatible'))
# Make sure we did at least two resizes
self.assertTrue(len(fdt.as_bytearray()) > FdtSw.INC_SIZE * 2)
class PyLibfdtRoTests(unittest.TestCase):
"""Test class for read-only pylibfdt access functions
This just tests a few simple cases. Most of the tests are in
PyLibfdtBasicTests.
Properties:
fdt: Device tree file used for testing
"""
def setUp(self):
"""Read in the device tree we use for testing"""
self.fdt = libfdt.FdtRo(open('test_tree1.dtb').read())
def testAccess(self):
"""Basic sanity check for the FdtRo class"""
node = self.fdt.path_offset('/subnode@1')
self.assertEqual('subnode1' + chr(0),
self.fdt.getprop(node, 'compatible'))
node = self.fdt.first_subnode(node)
self.assertEqual('this is a placeholder string\0string2\0',
self.fdt.getprop(node, 'placeholder'))
if __name__ == "__main__":
unittest.main()