From 76a36fbd2e0231565461c52ad4e7d8b1626acaf8 Mon Sep 17 00:00:00 2001
From: Christopher Obbard <christopher.obbard@linaro.org>
Date: Thu, 14 Nov 2024 13:44:49 +0000
Subject: [PATCH 1/2] Add gen_partition.py tool

gen_partition.py is a tool which can be used to generate partition.xml,
which is used with ptool to create partition table binaries and
rawprogram xml files. Include the tool in db-boot-tools since it is
quite useful for generation of rawprogram xml files.

Link: https://git.codelinaro.org/clo/le/meta-qti-bsp/-/blob/yocto.lnx.5.0.r10-rel/recipes-devtools/gen-partitions-tool/gen-partitions-tool-1.0/gen_partition.py?ref_type=heads
Signed-off-by: Christopher Obbard <christopher.obbard@linaro.org>
---
 gen_partition.py | 270 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 270 insertions(+)
 create mode 100644 gen_partition.py

diff --git a/gen_partition.py b/gen_partition.py
new file mode 100644
index 0000000..f9d5783
--- /dev/null
+++ b/gen_partition.py
@@ -0,0 +1,270 @@
+#!/usr/bin/python
+
+# Copyright (c) 2019, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+import re
+import getopt
+import xml.etree.ElementTree as ET
+from xml.dom import minidom
+from collections import OrderedDict
+
+def usage():
+   print("\n\tUsage: %s -i <input> -o <output> -m [partition_name1=image_filename1,partition_name2=image_filename2,...]\n\tVersion 1.0\n" %(sys.argv[0]))
+   sys.exit(1)
+
+##################################################################
+# defaults to be used
+disk_params = OrderedDict({
+   "type": "",
+   "size": "",
+   "SECTOR_SIZE_IN_BYTES": "512",
+   "WRITE_PROTECT_BOUNDARY_IN_KB": "65536",
+   "GROW_LAST_PARTITION_TO_FILL_DISK": "true",
+   "ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY": "true",
+   "PERFORMANCE_BOUNDARY_IN_KB": "4"
+})
+
+partition_entry_defaults = {
+   "label": "",
+   "size_in_kb": "",
+   "type": "00000000-0000-0000-0000-000000000000",
+   "bootable": "false",
+   "readonly": "true",
+   "filename": "",
+   "sparse" : "false"
+}
+
+##################################################################
+# store entries read from input file
+disk_entry = None
+partition_entries_dict = {}
+# store partition image map passed from command line
+partition_image_map = {}
+input_file = None
+output_xml = None
+
+def disk_options(argv):
+   for (opt, arg) in argv:
+      if opt in ['--type']:
+         disk_params["type"] = arg
+      elif opt in ['--size']:
+         disk_params["size"] = arg
+      elif opt in ['--sector-size-in-bytes']:
+         disk_params["SECTOR_SIZE_IN_BYTES"] = arg
+      elif opt in ['--write-protect-boundary']:
+         disk_params["WRITE_PROTECT_BOUNDARY_IN_KB"] = arg
+      elif opt in ['--grow-last-partition']:
+         disk_params["GROW_LAST_PARTITION_TO_FILL_DISK"] = "true"
+      elif opt in ['--align-partitions']:
+         disk_params["ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY"] = "true"
+         disk_params["PERFORMANCE_BOUNDARY_IN_KB"] = (int(arg)/1024)
+
+def partition_size_in_kb(size):
+    if not re.search('[a-zA-Z]+', size):
+        return int(size)/1024
+    if re.search('([0-9])*(?=([Kk]([Bb])*))', size):
+        return int(re.search('([0-9])*(?=([Kk]([Bb])*))', size).group(0))
+    if re.search('([0-9])*(?=([Mm]([Bb])*))', size):
+        return (int(re.search('([0-9])*(?=([Mm]([Bb])*))', size).group(0)) * 1024)
+    if re.search('([0-9])*(?=([Gg]([Bb])*))', size):
+        return (int(re.search('([0-9])*(?=([Gg]([Bb])*))', size).group(0)) * 1024 * 1024)
+
+def partition_options(argv):
+   partition_entry = partition_entry_defaults.copy()
+   for (opt, arg) in argv:
+      if opt in ['--lun']:
+         partition_entry["physical_partition"] = arg
+      elif opt in ['--name']:
+         partition_entry["label"] = arg
+      elif opt in ['--size']:
+         kbytes = partition_size_in_kb(arg)
+         partition_entry["size_in_kb"] = str(kbytes)
+      elif opt in ['--type-guid']:
+         partition_entry["type"] = arg
+      elif opt in ['--attributes']:
+         attribute_bits = int(arg,16)
+         if attribute_bits & (1<<2):
+            partition_entry["bootable"] = "true"
+         else:
+            partition_entry["bootable"] = "false"
+         if attribute_bits & (1<<60):
+            partition_entry["readonly"] = "true"
+         else:
+            partition_entry["readonly"] = "false"
+      elif opt in ['--filename']:
+         partition_entry["filename"] = arg
+      elif opt in ['--sparse']:
+         partition_entry["sparse"] = arg
+      if partition_entry["label"] in partition_image_map.keys():
+         partition_entry["filename"] = partition_image_map[partition_entry["label"]]
+   return partition_entry
+
+def parse_partition_entry(partition_entry):
+   opts_list = list(partition_entry.split(' '))
+   if opts_list[0] == "--partition":
+      try:
+         options, remainders = getopt.gnu_getopt(opts_list[1:], '',
+                                 ['lun=', 'name=', 'size=','type-guid=',
+                                  'filename=', 'attributes=', 'sparse='])
+         return partition_options(options)
+      except Exception as e:
+         print (str(e))
+         usage()
+
+   return None
+
+def parse_disk_entry(disk_entry):
+   opts_list = list(disk_entry.split(' '))
+   if opts_list[0] == "--disk":
+      try:
+         options, remainders = getopt.gnu_getopt(opts_list[1:], '',
+                                 ['type=', 'size=','sector-size-in-bytes=', 'write-protect-boundary=',
+                                  'grow-last-partition', 'align-partitions='])
+         disk_options(options)
+      except Exception as e:
+         print (str(e))
+         usage()
+
+def generate_ptool_xml (disk_params, partition_entries_dict, output_xml):
+   print("Generating ptool XML %s" %(output_xml))
+   root = ET.Element("configuration")
+   parser_instruction_text = ""
+
+   for key, value in disk_params.items():
+      if not key == 'size' and not key == 'type':
+         parser_instruction_text += '\n\t' + str(key) + '=' + str(value) + '\n\t'
+
+   parser_inst = ET.SubElement(root,"parser_instructions").text = (
+      parser_instruction_text
+   )
+
+   phy_part = ET.SubElement(root, "physical_partition")
+
+   for partition_index, entry in partition_entries_dict.items():
+      part_entry = parse_partition_entry(entry)
+      part = ET.SubElement(phy_part, "partition", attrib=part_entry)
+
+   xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml()
+   with open(output_xml, "w") as f:
+      f.write(xmlstr)
+
+def generate_ufs_xml (disk_params, partition_entries_dict, output_xml):
+   print("Generating UFS XML %s" %(output_xml))
+   root = ET.Element("configuration")
+   parser_instruction_text = ""
+
+   for key, value in disk_params.items():
+      if not key == 'size' and not key == 'type':
+         parser_instruction_text += '\n\t' + str(key) + '=' + str(value) + '\n\t'
+
+   parser_inst = ET.SubElement(root,"parser_instructions").text = (
+      parser_instruction_text
+   )
+   lun_index=0
+   while lun_index < 6:
+      phy_part = ET.SubElement(root, "physical_partition")
+
+      for partition_index, entry in partition_entries_dict.items():
+         part_entry = parse_partition_entry(entry)
+         if part_entry["physical_partition"] == str(lun_index):
+            del part_entry["physical_partition"]
+            part = ET.SubElement(phy_part, "partition", attrib=part_entry)
+      lun_index +=1
+
+   xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml()
+   with open(output_xml, "w") as f:
+      f.write(xmlstr)
+
+
+def generate_nand_mbn_gen_xml (disk_params, partition_entry):
+   print("Generating nand_mbn_gen XML")
+
+def generate_partition_xml (disk_entry, partition_entries_dict, output_xml):
+   parse_disk_entry(disk_entry)
+   if disk_params["type"] == "emmc":
+      generate_ptool_xml(disk_params, partition_entries_dict, output_xml)
+   elif disk_params["type"] == "nand":
+      generate_nand_mbn_gen_xml(disk_params, partition_entries_dict, output_xml)
+   elif disk_params["type"] == "ufs":
+      generate_ufs_xml(disk_params, partition_entries_dict, output_xml)
+
+###############################################################################
+# main
+disk_entry_err_msg = "contains more than one --disk entries"
+
+if len(sys.argv) < 3:
+   usage()
+
+try:
+   if sys.argv[1] == "-h" or sys.argv[1] == "--help":
+      usage()
+   try:
+      opts, rem = getopt.getopt(sys.argv[1:], "i:o:m:")
+      for (opt, arg) in opts:
+        if opt in ["-i"]:
+          input_file=arg
+        elif opt in ["-o"]:
+          output_xml=arg
+        elif opt in ["-m"]:
+          for mapping in arg.split(','):
+            tags=mapping.split("=")
+            if len(tags) > 1:
+              partition_image_map[tags[0]]=tags[1]
+            else:
+              usage()
+   except Exception as argerr:
+      print (str(argerr))
+      usage()
+   f = open(input_file)
+   line = f.readline()
+   partition_index = 0
+   while line:
+      if not re.search("^\s*#", line) and not re.search("^\s*$", line):
+         line = line.strip()
+         if re.search("^--disk", line):
+            if disk_entry == None:
+               disk_entry = line
+            else:
+               print("%s %s" %(sys.argv[1], disk_entry_err_msg))
+               print("%s\n%s" %(disk_entry, line))
+               sys.exit(1)
+         elif re.search("^--partition", line):
+            partition_entries_dict[partition_index] = line
+            partition_index += 1
+         else:
+            print("Ignoring %s" %(line))
+      line = f.readline()
+   f.close()
+except Exception as e:
+   print("Error: ", e)
+   sys.exit(1)
+
+generate_partition_xml(disk_entry, partition_entries_dict, output_xml)
+
+sys.exit(0)
-- 
GitLab


From b5e07e78080b8abc7950dd36b829d19d6e034e64 Mon Sep 17 00:00:00 2001
From: Christopher Obbard <christopher.obbard@linaro.org>
Date: Thu, 14 Nov 2024 14:48:41 +0000
Subject: [PATCH 2/2] gen_partition: avoid SyntaxWarning by using raw strings
 for regex patterns

Update regular expressions in gen_partition.py to use
raw string notation (r"...") to prevent invalid
escape sequence warnings for "\s". This change
ensures regex patterns are interpreted correctly by Python.

Signed-off-by: Christopher Obbard <christopher.obbard@linaro.org>
---
 gen_partition.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
 mode change 100644 => 100755 gen_partition.py

diff --git a/gen_partition.py b/gen_partition.py
old mode 100644
new mode 100755
index f9d5783..d23be6f
--- a/gen_partition.py
+++ b/gen_partition.py
@@ -245,16 +245,16 @@ try:
    line = f.readline()
    partition_index = 0
    while line:
-      if not re.search("^\s*#", line) and not re.search("^\s*$", line):
+      if not re.search(r"^\s*#", line) and not re.search(r"^\s*$", line):
          line = line.strip()
-         if re.search("^--disk", line):
+         if re.search(r"^--disk", line):
             if disk_entry == None:
                disk_entry = line
             else:
                print("%s %s" %(sys.argv[1], disk_entry_err_msg))
                print("%s\n%s" %(disk_entry, line))
                sys.exit(1)
-         elif re.search("^--partition", line):
+         elif re.search(r"^--partition", line):
             partition_entries_dict[partition_index] = line
             partition_index += 1
          else:
-- 
GitLab