Introduce rpi_boot partition option

A partition layout may specify a single rpi_boot partition. This
partition will show up in the protective mbr alongside the gpt table. We
will also change the dimensions of the MBR GPT protective partition to
prevent it from overlapping with the boot partition (which will crash
the Pi's firmware).

Change-Id: Ic8ec7ce4f06117cc90dc7c04e53aa837b36fb1bc
Test: Modified unit tests pass
Bug: 28915785
diff --git a/README b/README
index b4e6049..6287253 100644
--- a/README
+++ b/README
@@ -121,6 +121,12 @@
               numbers will be laid out before partitions with high
               'position' numbers. Default value is 0.
 
+ rpi_boot:    This is a Raspberry Pi boot partition. You can have one and only
+              one such partition. Declaring it introduces several hacks into the
+              protective MBR to allow this partition to appear as a boot
+              partition to the Pi's (MBR-only) boot loader, but still present a
+              GPT partition table to the Linux kernel after boot.
+
 For key/value-pairs involving sizes, either integers can be used, e.g.
 
  "size": 1048576
diff --git a/bpt_unittest.py b/bpt_unittest.py
index c2aa539..5abdf44 100755
--- a/bpt_unittest.py
+++ b/bpt_unittest.py
@@ -271,6 +271,16 @@
                     'test/expected_json_stacked_change_flags.bpt',
                     'test/expected_json_stacked_change_flags.bin')
 
+  def testRpiTables(self):
+    """Checks binary partition table output for Raspberry Pi.
+
+    This verifies that we generate the binary partition tables
+    correctly when we have a Raspberry Pi boot partition.
+    """
+    self._MakeTable(['test/rpi_boot.bpt'],
+                    'test/expected_rpi_boot_partitions.bpt',
+                    'test/expected_rpi_boot_partitions.bin')
+
   def testFileWithSyntaxErrors(self):
     """Check that we catch errors in JSON files in a structured way."""
     try:
diff --git a/bpttool b/bpttool
index 861fe6b..8b895f4 100755
--- a/bpttool
+++ b/bpttool
@@ -47,6 +47,7 @@
 JSON_KEYWORD_PARTITIONS_AB = 'ab'
 JSON_KEYWORD_PARTITIONS_AB_EXPANDED = 'ab_expanded'
 JSON_KEYWORD_PARTITIONS_POSITION = 'position'
+JSON_KEYWORD_PARTITIONS_RPIBOOT = 'rpi_boot'
 JSON_KEYWORD_AUTO = 'auto'
 
 # Possible values for the --type option of the query_partition
@@ -230,6 +231,7 @@
     ab_expanded: If True, the A/B partitions have been generated.
     ignore: If True, the partition should not be included in the final output.
     position: The requested position of the partition or 0 if it doesn't matter.
+    rpi_boot: Whether this is a Raspberry Pi boot partition.
   """
 
   def __init__(self):
@@ -245,6 +247,7 @@
     self.ab_expanded = False
     self.ignore = False
     self.position = 0
+    self.rpi_boot = False
 
   def add_info(self, pobj):
     """Add information to partition.
@@ -285,6 +288,9 @@
     value = pobj.get(JSON_KEYWORD_PARTITIONS_POSITION)
     if value:
       self.position = ParseNumber(value)
+    value = pobj.get(JSON_KEYWORD_PARTITIONS_RPIBOOT)
+    if value:
+      self.rpi_boot = True
 
   def expand_guid(self, guid_generator, partition_number):
     """Assign instance GUID and type GUID if required.
@@ -497,7 +503,8 @@
               '      "' + JSON_KEYWORD_PARTITIONS_IGNORE + '": {},\n'
               '      "' + JSON_KEYWORD_PARTITIONS_AB + '": {},\n'
               '      "' + JSON_KEYWORD_PARTITIONS_AB_EXPANDED + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_POSITION + '": {}\n'
+              '      "' + JSON_KEYWORD_PARTITIONS_POSITION + '": {},\n'
+              '      "' + JSON_KEYWORD_PARTITIONS_RPIBOOT + '": {}\n'
               '    }}{}\n').format(p.label,
                                    p.offset,
                                    p.size,
@@ -509,6 +516,7 @@
                                    'true' if p.ab else 'false',
                                    'true' if p.ab_expanded else 'false',
                                    p.position,
+                                   'true' if p.rpi_boot else 'false',
                                    '' if n == len(partitions) - 1 else ',')
     ret += ('  ]\n'
             '}\n')
@@ -536,11 +544,28 @@
     s = lba % num_sectors
     return [h, (((c>>8) & 0x03)<<6) | (s & 0x3f), c & 0xff]
 
-  def _generate_protective_mbr(self, settings):
+  def _generate_mbr_entry(self, start_chs, end_chs, lba_start, lba_size,
+                          mbr_type):
+    return struct.pack('<B'        # Status.
+                       'BBB'       # CHS start.
+                       'B'         # Partition type.
+                       'BBB'       # CHS end.
+                       'I'         # LBA of partition start.
+                       'I',        # Number of sectors in partition.
+                       0x00,
+                       start_chs[0], start_chs[1], start_chs[2],
+                       mbr_type,
+                       end_chs[0], end_chs[1], end_chs[2],
+                       lba_start,
+                       lba_size)
+
+  def _generate_protective_mbr(self, settings, rpi_boot_partition=None):
     """Generate Protective MBR.
 
     Arguments:
       settings: A Settings object.
+      rpi_boot_partition: If set, a special boot partition to be mentioned
+                          in the MBR
 
     Returns:
       A string with the binary protective MBR (512 bytes).
@@ -549,25 +574,35 @@
     #
     # The first partition starts at offset 446 (0x1be).
     lba_start = 1
-    lba_end = settings.disk_size/DISK_SECTOR_SIZE - 1
+    lba_end = 1
+    if rpi_boot_partition is None:
+      lba_end = settings.disk_size/DISK_SECTOR_SIZE - 1
+    lba_size = lba_end
+
     start_chs = self._lba_to_chs(lba_start)
     end_chs = self._lba_to_chs(lba_end)
+
+    parts = self._generate_mbr_entry(start_chs, end_chs,
+            lba_start, lba_size, 0xee)
+
+    if rpi_boot_partition:
+      boot_lba_start = rpi_boot_partition.offset
+      boot_lba_size = rpi_boot_partition.size
+      boot_lba_end = boot_lba_start + boot_lba_size - 1
+
+      boot_start_chs = self._lba_to_chs(boot_lba_start)
+      boot_end_chs = self._lba_to_chs(boot_lba_end)
+      parts = struct.pack('16s'       # The boot partition
+                          '16s',      # The GPT partition
+                          self._generate_mbr_entry(boot_start_chs, boot_end_chs,
+                              boot_lba_start, boot_lba_size, 0x06),
+                          parts)
+
     pmbr = struct.pack('<446s'     # Bootloader code
-                       'B'         # Status.
-                       'BBB'       # CHS start.
-                       'B'         # Partition type.
-                       'BBB'       # CHS end.
-                       'I'         # LBA of partition start.
-                       'I'         # Number of sectors in partition.
-                       '48x'       # Padding to get to offset 510 (0x1fe).
+                       '64s'       # Partition entries.
                        'BB',       # Boot signature.
                        '\xfa\xeb\xfe', # cli ; jmp $ (x86)
-                       0x00,
-                       start_chs[0], start_chs[1], start_chs[2],
-                       0xee,       # MBR Partition Type: GPT protective MBR.
-                       end_chs[0], end_chs[1], end_chs[2],
-                       1,          # LBA start
-                       lba_end,
+                       parts,
                        0x55, 0xaa)
     return pmbr
 
@@ -671,7 +706,16 @@
     Returns:
       A bytearray() object.
     """
-    protective_mbr = self._generate_protective_mbr(settings)
+
+    rpi_boot_partition = None
+    for partition in partitions:
+      if partition.rpi_boot:
+        if rpi_boot_partition:
+          raise BptError('More than one Raspberry Pi Boot '
+                         'partition specified.\n')
+        rpi_boot_partition = partition
+
+    protective_mbr = self._generate_protective_mbr(settings, rpi_boot_partition)
     primary_gpt = self._generate_gpt(partitions, settings)
     secondary_gpt = self._generate_gpt(partitions, settings, primary=False)
     ret = protective_mbr + primary_gpt + secondary_gpt
diff --git a/test/base.bpt b/test/base.bpt
index aa1e445..5a183e9 100644
--- a/test/base.bpt
+++ b/test/base.bpt
@@ -5,27 +5,31 @@
             "label": "boot",
             "size": "32 MiB",
             "guid": "auto",
-            "type_guid": "brillo_boot"
+            "type_guid": "brillo_boot",
+            "rpi_boot": false
         },
         {
             "ab": true,
             "label": "system",
             "size": "512 MiB",
             "guid": "auto",
-            "type_guid": "brillo_system"
+            "type_guid": "brillo_system",
+            "rpi_boot": false
         },
         {
             "ab": true,
             "label": "odm",
             "size": "1 GiB",
             "guid": "auto",
-            "type_guid": "brillo_odm"
+            "type_guid": "brillo_odm",
+            "rpi_boot": false
         },
         {
             "label": "userdata",
             "grow": true,
             "guid": "auto",
-            "type_guid": "brillo_userdata"
+            "type_guid": "brillo_userdata",
+            "rpi_boot": false
         }
     ]
 }
diff --git a/test/expected_json_alignment.bpt b/test/expected_json_alignment.bpt
index e1a13bf..0e5f958 100644
--- a/test/expected_json_alignment.bpt
+++ b/test/expected_json_alignment.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_base.bpt b/test/expected_json_base.bpt
index a496c2a..e5ad459 100644
--- a/test/expected_json_base.bpt
+++ b/test/expected_json_base.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_disk_guid.bpt b/test/expected_json_disk_guid.bpt
index bbbf447..3d3e155 100644
--- a/test/expected_json_disk_guid.bpt
+++ b/test/expected_json_disk_guid.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_size.bpt b/test/expected_json_size.bpt
index 189dc9c..08cb25f 100644
--- a/test/expected_json_size.bpt
+++ b/test/expected_json_size.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_change_ab_size.bpt b/test/expected_json_stacked_change_ab_size.bpt
index c16b533..579a386 100644
--- a/test/expected_json_stacked_change_ab_size.bpt
+++ b/test/expected_json_stacked_change_ab_size.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_change_flags.bpt b/test/expected_json_stacked_change_flags.bpt
index 12c5cdc..b419787 100644
--- a/test/expected_json_stacked_change_flags.bpt
+++ b/test/expected_json_stacked_change_flags.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_ignore.bpt b/test/expected_json_stacked_ignore.bpt
index 5683b07..5fb9051 100644
--- a/test/expected_json_stacked_ignore.bpt
+++ b/test/expected_json_stacked_ignore.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_new_partition.bpt b/test/expected_json_stacked_new_partition.bpt
index 83636e1..d50d733 100644
--- a/test/expected_json_stacked_new_partition.bpt
+++ b/test/expected_json_stacked_new_partition.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "my_data_partition",
@@ -108,7 +115,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_new_partition_on_top.bpt b/test/expected_json_stacked_new_partition_on_top.bpt
index 9f6efae..4ab7d78 100644
--- a/test/expected_json_stacked_new_partition_on_top.bpt
+++ b/test/expected_json_stacked_new_partition_on_top.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "my_partition_on_top_of_json",
@@ -108,7 +115,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_override_settings.bpt b/test/expected_json_stacked_override_settings.bpt
index 2d8979c..667fc5c 100644
--- a/test/expected_json_stacked_override_settings.bpt
+++ b/test/expected_json_stacked_override_settings.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot-1",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system-0",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system-1",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm-0",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm-1",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_positions.bpt b/test/expected_json_stacked_positions.bpt
index 8a173cc..15b5226 100644
--- a/test/expected_json_stacked_positions.bpt
+++ b/test/expected_json_stacked_positions.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 1
+      "position": 1,
+      "rpi_boot": false
     },
     {
       "label": "my_data_2",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 2
+      "position": 2,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 3
+      "position": 3,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 3
+      "position": 3,
+      "rpi_boot": false
     },
     {
       "label": "my_data_3",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 4
+      "position": 4,
+      "rpi_boot": false
     },
     {
       "label": "boot_a",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -108,7 +115,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -121,7 +129,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -134,7 +143,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_stacked_size.bpt b/test/expected_json_stacked_size.bpt
index 06095d1..38b5d8a 100644
--- a/test/expected_json_stacked_size.bpt
+++ b/test/expected_json_stacked_size.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot_b",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_a",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system_b",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_a",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm_b",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_json_suffixes.bpt b/test/expected_json_suffixes.bpt
index 8155077..a6c805a 100644
--- a/test/expected_json_suffixes.bpt
+++ b/test/expected_json_suffixes.bpt
@@ -17,7 +17,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "boot-B",
@@ -30,7 +31,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system-A",
@@ -43,7 +45,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "system-B",
@@ -56,7 +59,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm-A",
@@ -69,7 +73,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "odm-B",
@@ -82,7 +87,8 @@
       "ignore": false,
       "ab": true,
       "ab_expanded": true,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     },
     {
       "label": "userdata",
@@ -95,7 +101,8 @@
       "ignore": false,
       "ab": false,
       "ab_expanded": false,
-      "position": 0
+      "position": 0,
+      "rpi_boot": false
     }
   ]
 }
diff --git a/test/expected_rpi_boot_partitions.bin b/test/expected_rpi_boot_partitions.bin
new file mode 100644
index 0000000..1c9b8df
--- /dev/null
+++ b/test/expected_rpi_boot_partitions.bin
Binary files differ
diff --git a/test/expected_rpi_boot_partitions.bpt b/test/expected_rpi_boot_partitions.bpt
new file mode 100644
index 0000000..92c662a
--- /dev/null
+++ b/test/expected_rpi_boot_partitions.bpt
@@ -0,0 +1,108 @@
+{
+  "settings": {
+    "ab_suffixes": ["_a", "_b"],
+    "disk_size": 4294967296,
+    "disk_alignment": 4096,
+    "disk_guid": "01234567-89ab-cdef-0123-000000000000"
+  },
+  "partitions": [
+    {
+      "label": "boot_pi",
+      "offset": 20480,
+      "size": 33554432,
+      "grow": false,
+      "guid": "01234567-89ab-cdef-0123-000000000001",
+      "type_guid": "314f99d5-b2bf-4883-8d03-e2f2ce507d6a",
+      "flags": "0x0000000000000000",
+      "ignore": false,
+      "ab": false,
+      "ab_expanded": false,
+      "position": 0,
+      "rpi_boot": true
+    },
+    {
+      "label": "system_a",
+      "offset": 33574912,
+      "size": 536870912,
+      "grow": false,
+      "guid": "01234567-89ab-cdef-0123-000000000002",
+      "type_guid": "0f2778c4-5cc1-4300-8670-6c88b7e57ed6",
+      "flags": "0x0000000000000000",
+      "ignore": false,
+      "ab": true,
+      "ab_expanded": true,
+      "position": 0,
+      "rpi_boot": false
+    },
+    {
+      "label": "system_b",
+      "offset": 570445824,
+      "size": 536870912,
+      "grow": false,
+      "guid": "01234567-89ab-cdef-0123-000000000003",
+      "type_guid": "0f2778c4-5cc1-4300-8670-6c88b7e57ed6",
+      "flags": "0x0000000000000000",
+      "ignore": false,
+      "ab": true,
+      "ab_expanded": true,
+      "position": 0,
+      "rpi_boot": false
+    },
+    {
+      "label": "odm_a",
+      "offset": 1107316736,
+      "size": 536870912,
+      "grow": false,
+      "guid": "01234567-89ab-cdef-0123-000000000004",
+      "type_guid": "e99d84d7-2c1b-44cf-8c58-effae2dc2558",
+      "flags": "0x0000000000000000",
+      "ignore": false,
+      "ab": true,
+      "ab_expanded": true,
+      "position": 0,
+      "rpi_boot": false
+    },
+    {
+      "label": "odm_b",
+      "offset": 1644187648,
+      "size": 536870912,
+      "grow": false,
+      "guid": "01234567-89ab-cdef-0123-000000000005",
+      "type_guid": "e99d84d7-2c1b-44cf-8c58-effae2dc2558",
+      "flags": "0x0000000000000000",
+      "ignore": false,
+      "ab": true,
+      "ab_expanded": true,
+      "position": 0,
+      "rpi_boot": false
+    },
+    {
+      "label": "misc",
+      "offset": 2181058560,
+      "size": 1048576,
+      "grow": false,
+      "guid": "01234567-89ab-cdef-0123-000000000006",
+      "type_guid": "6b2378b0-0fbc-4aa9-a4f6-4d6e17281c47",
+      "flags": "0x0000000000000000",
+      "ignore": false,
+      "ab": false,
+      "ab_expanded": false,
+      "position": 0,
+      "rpi_boot": false
+    },
+    {
+      "label": "userdata",
+      "offset": 2182107136,
+      "size": 2112839680,
+      "grow": true,
+      "guid": "01234567-89ab-cdef-0123-000000000007",
+      "type_guid": "0bb7e6ed-4424-49c0-9372-7fbab465ab4c",
+      "flags": "0x0000000000000000",
+      "ignore": false,
+      "ab": false,
+      "ab_expanded": false,
+      "position": 0,
+      "rpi_boot": false
+    }
+  ]
+}
diff --git a/test/rpi_boot.bpt b/test/rpi_boot.bpt
new file mode 100644
index 0000000..aa12e60
--- /dev/null
+++ b/test/rpi_boot.bpt
@@ -0,0 +1,34 @@
+{
+    "settings": {
+        "disk_size": "4 GiB"
+    },
+    "partitions": [
+        {
+            "rpi_boot": true,
+            "label": "boot_pi",
+            "size": "32 MiB"
+        },
+        {
+            "ab": true,
+            "label": "system",
+            "size": "512 MiB",
+            "type_guid": "brillo_system"
+        },
+        {
+            "ab": true,
+            "label": "odm",
+            "size": "512 MiB",
+            "type_guid": "brillo_odm"
+        },
+        {
+            "label": "misc",
+            "size": "1 MiB",
+            "type_guid": "brillo_misc"
+        },
+        {
+            "label": "userdata",
+            "grow": true,
+            "type_guid": "brillo_userdata"
+        }
+    ]
+}