binman: Support an entry that holds text

It is useful to able to write an identifying string to the image within an
entry. Add a 'text' entry type to handle this. The actual text is
typically passed to binman on the command line. The text is not itself
nul-terminated but this can be achieved if required by setting the size of
the entry to something larger than the text.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/tools/binman/etype/text.py b/tools/binman/etype/text.py
new file mode 100644
index 0000000..1c69afa
--- /dev/null
+++ b/tools/binman/etype/text.py
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+from collections import OrderedDict
+
+from entry import Entry, EntryArg
+import fdt_util
+
+
+class Entry_text(Entry):
+    """An entry which contains text
+
+    The text can be provided either in the node itself or by a command-line
+    argument.
+
+    Example node:
+
+        text {
+            size = <50>;
+            text-label = "message";
+        };
+
+    You can then use:
+
+        binman -amessage="this is my message"
+
+    and binman will insert that string into the entry.
+
+    It is also possible to put the string directly in the node:
+
+        text {
+            size = <8>;
+            text-label = "message";
+            message = "a message directly in the node"
+        };
+
+    The text is not itself nul-terminated. This can be achieved, if required,
+    by setting the size of the entry to something larger than the text.
+    """
+    def __init__(self, section, etype, node):
+        Entry.__init__(self, section, etype, node)
+        self.text_label, = self.GetEntryArgsOrProps(
+            [EntryArg('text-label', str)])
+        self.value, = self.GetEntryArgsOrProps([EntryArg(self.text_label, str)])
+
+    def ObtainContents(self):
+        self.SetContents(self.value)
+        return True
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index c54cd12..6968896 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -41,6 +41,9 @@
 CMC_DATA              = 'cmc'
 VBT_DATA              = 'vbt'
 MRC_DATA              = 'mrc'
+TEXT_DATA             = 'text'
+TEXT_DATA2            = 'text2'
+TEXT_DATA3            = 'text3'
 
 class TestFunctional(unittest.TestCase):
     """Functional tests for binman
@@ -1161,6 +1164,19 @@
         self.assertIn('GetArg() internal error: Unknown data type ',
                       str(e.exception))
 
+    def testText(self):
+        """Test for a text entry type"""
+        entry_args = {
+            'test-id': TEXT_DATA,
+            'test-id2': TEXT_DATA2,
+            'test-id3': TEXT_DATA3,
+        }
+        data, _, _, _ = self._DoReadFileDtb('66_text.dts',
+                                            entry_args=entry_args)
+        expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
+                    TEXT_DATA3 + 'some text')
+        self.assertEqual(expected, data)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/66_text.dts b/tools/binman/test/66_text.dts
new file mode 100644
index 0000000..59b1fed
--- /dev/null
+++ b/tools/binman/test/66_text.dts
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		text {
+			size = <8>;
+			text-label = "test-id";
+		};
+		text2 {
+			type = "text";
+			text-label = "test-id2";
+		};
+		text3 {
+			type = "text";
+			text-label = "test-id3";
+		};
+		/* This one does not use command-line args */
+		text4 {
+			type = "text";
+			text-label = "test-id4";
+			test-id4 = "some text";
+		};
+	};
+};