fdt: Use an Enum for the data type

Use an Enum instead of the current ad-hoc constants, so that there is a
data type associated with each 'type' value.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2020-11-08 20:36:17 -07:00
parent ddaa949785
commit 5ea9dccf02
5 changed files with 77 additions and 59 deletions

View File

@ -50,37 +50,37 @@ class TestFdt(unittest.TestCase):
self.assertEquals('me.bin', val) self.assertEquals('me.bin', val)
prop = node.props['intval'] prop = node.props['intval']
self.assertEquals(fdt.TYPE_INT, prop.type) self.assertEquals(fdt.Type.INT, prop.type)
self.assertEquals(3, fdt_util.GetInt(node, 'intval')) self.assertEquals(3, fdt_util.GetInt(node, 'intval'))
prop = node.props['intarray'] prop = node.props['intarray']
self.assertEquals(fdt.TYPE_INT, prop.type) self.assertEquals(fdt.Type.INT, prop.type)
self.assertEquals(list, type(prop.value)) self.assertEquals(list, type(prop.value))
self.assertEquals(2, len(prop.value)) self.assertEquals(2, len(prop.value))
self.assertEquals([5, 6], self.assertEquals([5, 6],
[fdt_util.fdt32_to_cpu(val) for val in prop.value]) [fdt_util.fdt32_to_cpu(val) for val in prop.value])
prop = node.props['byteval'] prop = node.props['byteval']
self.assertEquals(fdt.TYPE_BYTE, prop.type) self.assertEquals(fdt.Type.BYTE, prop.type)
self.assertEquals(chr(8), prop.value) self.assertEquals(chr(8), prop.value)
prop = node.props['bytearray'] prop = node.props['bytearray']
self.assertEquals(fdt.TYPE_BYTE, prop.type) self.assertEquals(fdt.Type.BYTE, prop.type)
self.assertEquals(list, type(prop.value)) self.assertEquals(list, type(prop.value))
self.assertEquals(str, type(prop.value[0])) self.assertEquals(str, type(prop.value[0]))
self.assertEquals(3, len(prop.value)) self.assertEquals(3, len(prop.value))
self.assertEquals([chr(1), '#', '4'], prop.value) self.assertEquals([chr(1), '#', '4'], prop.value)
prop = node.props['longbytearray'] prop = node.props['longbytearray']
self.assertEquals(fdt.TYPE_INT, prop.type) self.assertEquals(fdt.Type.INT, prop.type)
self.assertEquals(0x090a0b0c, fdt_util.GetInt(node, 'longbytearray')) self.assertEquals(0x090a0b0c, fdt_util.GetInt(node, 'longbytearray'))
prop = node.props['stringval'] prop = node.props['stringval']
self.assertEquals(fdt.TYPE_STRING, prop.type) self.assertEquals(fdt.Type.STRING, prop.type)
self.assertEquals('message2', fdt_util.GetString(node, 'stringval')) self.assertEquals('message2', fdt_util.GetString(node, 'stringval'))
prop = node.props['stringarray'] prop = node.props['stringarray']
self.assertEquals(fdt.TYPE_STRING, prop.type) self.assertEquals(fdt.Type.STRING, prop.type)
self.assertEquals(list, type(prop.value)) self.assertEquals(list, type(prop.value))
self.assertEquals(3, len(prop.value)) self.assertEquals(3, len(prop.value))
self.assertEquals(['another', 'multi-word', 'message'], prop.value) self.assertEquals(['another', 'multi-word', 'message'], prop.value)

View File

@ -35,13 +35,13 @@ PROP_IGNORE_LIST = [
'u-boot,dm-spl', 'u-boot,dm-spl',
] ]
# C type declarations for the tyues we support # C type declarations for the types we support
TYPE_NAMES = { TYPE_NAMES = {
fdt.TYPE_INT: 'fdt32_t', fdt.Type.INT: 'fdt32_t',
fdt.TYPE_BYTE: 'unsigned char', fdt.Type.BYTE: 'unsigned char',
fdt.TYPE_STRING: 'const char *', fdt.Type.STRING: 'const char *',
fdt.TYPE_BOOL: 'bool', fdt.Type.BOOL: 'bool',
fdt.TYPE_INT64: 'fdt64_t', fdt.Type.INT64: 'fdt64_t',
} }
STRUCT_PREFIX = 'dtd_' STRUCT_PREFIX = 'dtd_'
@ -106,17 +106,17 @@ def get_value(ftype, value):
type: Data type (fdt_util) type: Data type (fdt_util)
value: Data value, as a string of bytes value: Data value, as a string of bytes
""" """
if ftype == fdt.TYPE_INT: if ftype == fdt.Type.INT:
return '%#x' % fdt_util.fdt32_to_cpu(value) return '%#x' % fdt_util.fdt32_to_cpu(value)
elif ftype == fdt.TYPE_BYTE: elif ftype == fdt.Type.BYTE:
return '%#x' % tools.ToByte(value[0]) return '%#x' % tools.ToByte(value[0])
elif ftype == fdt.TYPE_STRING: elif ftype == fdt.Type.STRING:
# Handle evil ACPI backslashes by adding another backslash before them. # Handle evil ACPI backslashes by adding another backslash before them.
# So "\\_SB.GPO0" in the device tree effectively stays like that in C # So "\\_SB.GPO0" in the device tree effectively stays like that in C
return '"%s"' % value.replace('\\', '\\\\') return '"%s"' % value.replace('\\', '\\\\')
elif ftype == fdt.TYPE_BOOL: elif ftype == fdt.Type.BOOL:
return 'true' return 'true'
elif ftype == fdt.TYPE_INT64: elif ftype == fdt.Type.INT64:
return '%#x' % value return '%#x' % value
def get_compat_name(node): def get_compat_name(node):
@ -435,7 +435,7 @@ class DtbPlatdata(object):
na, ns = self.get_num_cells(node) na, ns = self.get_num_cells(node)
total = na + ns total = na + ns
if reg.type != fdt.TYPE_INT: if reg.type != fdt.Type.INT:
raise ValueError("Node '%s' reg property is not an int" % raise ValueError("Node '%s' reg property is not an int" %
node.name) node.name)
if len(reg.value) % total: if len(reg.value) % total:
@ -445,7 +445,7 @@ class DtbPlatdata(object):
reg.na = na reg.na = na
reg.ns = ns reg.ns = ns
if na != 1 or ns != 1: if na != 1 or ns != 1:
reg.type = fdt.TYPE_INT64 reg.type = fdt.Type.INT64
i = 0 i = 0
new_value = [] new_value = []
val = reg.value val = reg.value

View File

@ -5,6 +5,7 @@
# Written by Simon Glass <sjg@chromium.org> # Written by Simon Glass <sjg@chromium.org>
# #
from enum import IntEnum
import struct import struct
import sys import sys
@ -22,7 +23,25 @@ from patman import tools
# so it is fairly efficient. # so it is fairly efficient.
# A list of types we support # A list of types we support
(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, TYPE_INT64) = range(5) class Type(IntEnum):
(BYTE, INT, STRING, BOOL, INT64) = range(5)
def is_wider_than(self, other):
"""Check if another type is 'wider' than this one
A wider type is one that holds more information than an earlier one,
similar to the concept of type-widening in C.
This uses a simple arithmetic comparison, since type values are in order
from narrowest (BYTE) to widest (INT64).
Args:
other: Other type to compare against
Return:
True if the other type is wider
"""
return self.value > other.value
def CheckErr(errnum, msg): def CheckErr(errnum, msg):
if errnum: if errnum:
@ -41,9 +60,9 @@ def BytesToValue(data):
Type of data Type of data
Data, either a single element or a list of elements. Each element Data, either a single element or a list of elements. Each element
is one of: is one of:
TYPE_STRING: str/bytes value from the property Type.STRING: str/bytes value from the property
TYPE_INT: a byte-swapped integer stored as a 4-byte str/bytes Type.INT: a byte-swapped integer stored as a 4-byte str/bytes
TYPE_BYTE: a byte stored as a single-byte str/bytes Type.BYTE: a byte stored as a single-byte str/bytes
""" """
data = bytes(data) data = bytes(data)
size = len(data) size = len(data)
@ -63,21 +82,21 @@ def BytesToValue(data):
is_string = False is_string = False
if is_string: if is_string:
if count == 1: if count == 1:
return TYPE_STRING, strings[0].decode() return Type.STRING, strings[0].decode()
else: else:
return TYPE_STRING, [s.decode() for s in strings[:-1]] return Type.STRING, [s.decode() for s in strings[:-1]]
if size % 4: if size % 4:
if size == 1: if size == 1:
return TYPE_BYTE, tools.ToChar(data[0]) return Type.BYTE, tools.ToChar(data[0])
else: else:
return TYPE_BYTE, [tools.ToChar(ch) for ch in list(data)] return Type.BYTE, [tools.ToChar(ch) for ch in list(data)]
val = [] val = []
for i in range(0, size, 4): for i in range(0, size, 4):
val.append(data[i:i + 4]) val.append(data[i:i + 4])
if size == 4: if size == 4:
return TYPE_INT, val[0] return Type.INT, val[0]
else: else:
return TYPE_INT, val return Type.INT, val
class Prop: class Prop:
@ -97,7 +116,7 @@ class Prop:
self.bytes = bytes(data) self.bytes = bytes(data)
self.dirty = False self.dirty = False
if not data: if not data:
self.type = TYPE_BOOL self.type = Type.BOOL
self.value = True self.value = True
return return
self.type, self.value = BytesToValue(bytes(data)) self.type, self.value = BytesToValue(bytes(data))
@ -128,9 +147,8 @@ class Prop:
update the current property to be like the second, since it is less update the current property to be like the second, since it is less
specific. specific.
""" """
if newprop.type < self.type: if self.type.is_wider_than(newprop.type):
# Special handling to convert an int into bytes if self.type == Type.INT and newprop.type == Type.BYTE:
if self.type == TYPE_INT and newprop.type == TYPE_BYTE:
if type(self.value) == list: if type(self.value) == list:
new_value = [] new_value = []
for val in self.value: for val in self.value:
@ -155,11 +173,11 @@ class Prop:
Returns: Returns:
A single value of the given type A single value of the given type
""" """
if type == TYPE_BYTE: if type == Type.BYTE:
return chr(0) return chr(0)
elif type == TYPE_INT: elif type == Type.INT:
return struct.pack('>I', 0); return struct.pack('>I', 0);
elif type == TYPE_STRING: elif type == Type.STRING:
return '' return ''
else: else:
return True return True
@ -184,7 +202,7 @@ class Prop:
""" """
self.bytes = struct.pack('>I', val); self.bytes = struct.pack('>I', val);
self.value = self.bytes self.value = self.bytes
self.type = TYPE_INT self.type = Type.INT
self.dirty = True self.dirty = True
def SetData(self, bytes): def SetData(self, bytes):

View File

@ -134,13 +134,13 @@ class TestDtoc(unittest.TestCase):
def test_get_value(self): def test_get_value(self):
"""Test operation of get_value() function""" """Test operation of get_value() function"""
self.assertEqual('0x45', self.assertEqual('0x45',
get_value(fdt.TYPE_INT, struct.pack('>I', 0x45))) get_value(fdt.Type.INT, struct.pack('>I', 0x45)))
self.assertEqual('0x45', self.assertEqual('0x45',
get_value(fdt.TYPE_BYTE, struct.pack('<I', 0x45))) get_value(fdt.Type.BYTE, struct.pack('<I', 0x45)))
self.assertEqual('0x0', self.assertEqual('0x0',
get_value(fdt.TYPE_BYTE, struct.pack('>I', 0x45))) get_value(fdt.Type.BYTE, struct.pack('>I', 0x45)))
self.assertEqual('"test"', get_value(fdt.TYPE_STRING, 'test')) self.assertEqual('"test"', get_value(fdt.Type.STRING, 'test'))
self.assertEqual('true', get_value(fdt.TYPE_BOOL, None)) self.assertEqual('true', get_value(fdt.Type.BOOL, None))
def test_get_compat_name(self): def test_get_compat_name(self):
"""Test operation of get_compat_name() function""" """Test operation of get_compat_name() function"""

View File

@ -19,7 +19,7 @@ sys.path.insert(1, os.path.join(our_path, '..'))
from dtoc import fdt from dtoc import fdt
from dtoc import fdt_util from dtoc import fdt_util
from dtoc.fdt_util import fdt32_to_cpu from dtoc.fdt_util import fdt32_to_cpu
from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, BytesToValue from fdt import Type, BytesToValue
import libfdt import libfdt
from patman import command from patman import command
from patman import test_util from patman import test_util
@ -127,7 +127,7 @@ class TestFdt(unittest.TestCase):
def testBytesToValue(self): def testBytesToValue(self):
self.assertEqual(BytesToValue(b'this\0is\0'), self.assertEqual(BytesToValue(b'this\0is\0'),
(TYPE_STRING, ['this', 'is'])) (Type.STRING, ['this', 'is']))
class TestNode(unittest.TestCase): class TestNode(unittest.TestCase):
"""Test operation of the Node class""" """Test operation of the Node class"""
@ -249,46 +249,46 @@ class TestProp(unittest.TestCase):
def testMakeProp(self): def testMakeProp(self):
"""Test we can convert all the the types that are supported""" """Test we can convert all the the types that are supported"""
prop = self._ConvertProp('boolval') prop = self._ConvertProp('boolval')
self.assertEqual(fdt.TYPE_BOOL, prop.type) self.assertEqual(Type.BOOL, prop.type)
self.assertEqual(True, prop.value) self.assertEqual(True, prop.value)
prop = self._ConvertProp('intval') prop = self._ConvertProp('intval')
self.assertEqual(fdt.TYPE_INT, prop.type) self.assertEqual(Type.INT, prop.type)
self.assertEqual(1, fdt32_to_cpu(prop.value)) self.assertEqual(1, fdt32_to_cpu(prop.value))
prop = self._ConvertProp('intarray') prop = self._ConvertProp('intarray')
self.assertEqual(fdt.TYPE_INT, prop.type) self.assertEqual(Type.INT, prop.type)
val = [fdt32_to_cpu(val) for val in prop.value] val = [fdt32_to_cpu(val) for val in prop.value]
self.assertEqual([2, 3, 4], val) self.assertEqual([2, 3, 4], val)
prop = self._ConvertProp('byteval') prop = self._ConvertProp('byteval')
self.assertEqual(fdt.TYPE_BYTE, prop.type) self.assertEqual(Type.BYTE, prop.type)
self.assertEqual(5, ord(prop.value)) self.assertEqual(5, ord(prop.value))
prop = self._ConvertProp('longbytearray') prop = self._ConvertProp('longbytearray')
self.assertEqual(fdt.TYPE_BYTE, prop.type) self.assertEqual(Type.BYTE, prop.type)
val = [ord(val) for val in prop.value] val = [ord(val) for val in prop.value]
self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val) self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
prop = self._ConvertProp('stringval') prop = self._ConvertProp('stringval')
self.assertEqual(fdt.TYPE_STRING, prop.type) self.assertEqual(Type.STRING, prop.type)
self.assertEqual('message', prop.value) self.assertEqual('message', prop.value)
prop = self._ConvertProp('stringarray') prop = self._ConvertProp('stringarray')
self.assertEqual(fdt.TYPE_STRING, prop.type) self.assertEqual(Type.STRING, prop.type)
self.assertEqual(['multi-word', 'message'], prop.value) self.assertEqual(['multi-word', 'message'], prop.value)
prop = self._ConvertProp('notstring') prop = self._ConvertProp('notstring')
self.assertEqual(fdt.TYPE_BYTE, prop.type) self.assertEqual(Type.BYTE, prop.type)
val = [ord(val) for val in prop.value] val = [ord(val) for val in prop.value]
self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val) self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
def testGetEmpty(self): def testGetEmpty(self):
"""Tests the GetEmpty() function for the various supported types""" """Tests the GetEmpty() function for the various supported types"""
self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL)) self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
self.assertEqual(chr(0), fdt.Prop.GetEmpty(fdt.TYPE_BYTE)) self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(fdt.TYPE_INT)) self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
self.assertEqual('', fdt.Prop.GetEmpty(fdt.TYPE_STRING)) self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
def testGetOffset(self): def testGetOffset(self):
"""Test we can get the offset of a property""" """Test we can get the offset of a property"""
@ -304,13 +304,13 @@ class TestProp(unittest.TestCase):
# No action # No action
prop2 = node2.props['intval'] prop2 = node2.props['intval']
prop.Widen(prop2) prop.Widen(prop2)
self.assertEqual(fdt.TYPE_INT, prop.type) self.assertEqual(Type.INT, prop.type)
self.assertEqual(1, fdt32_to_cpu(prop.value)) self.assertEqual(1, fdt32_to_cpu(prop.value))
# Convert singla value to array # Convert singla value to array
prop2 = self.node.props['intarray'] prop2 = self.node.props['intarray']
prop.Widen(prop2) prop.Widen(prop2)
self.assertEqual(fdt.TYPE_INT, prop.type) self.assertEqual(Type.INT, prop.type)
self.assertTrue(isinstance(prop.value, list)) self.assertTrue(isinstance(prop.value, list))
# A 4-byte array looks like a single integer. When widened by a longer # A 4-byte array looks like a single integer. When widened by a longer