2 * Copyright (C) 2018-2019 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #include <nbdkit-plugin.h>
45 #include "byte-swapping.h"
46 #include "efi-crc32.h"
48 #include "isaligned.h"
52 #include "virtual-disk.h"
54 #define PARTITION_TYPE_GUID "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
56 static void create_gpt_protective_mbr (struct virtual_disk
*disk
,
58 static void create_gpt_partition_header (struct virtual_disk
*disk
,
59 const void *pt
, bool is_primary
,
61 static void create_gpt_partition_table (struct virtual_disk
*disk
,
64 /* Initialize the partition table structures. */
66 create_partition_table (struct virtual_disk
*disk
)
68 create_gpt_protective_mbr (disk
, disk
->protective_mbr
);
70 create_gpt_partition_table (disk
, disk
->pt
);
72 create_gpt_partition_header (disk
, disk
->pt
, true, disk
->primary_header
);
73 create_gpt_partition_header (disk
, disk
->pt
, false, disk
->secondary_header
);
79 chs_too_large (unsigned char *out
)
81 const int c
= 1023, h
= 254, s
= 63;
84 out
[1] = (c
& 0x300) >> 2 | s
;
89 create_mbr_partition_table_entry (const struct region
*region
,
90 bool bootable
, int partition_id
,
93 uint64_t start_sector
, nr_sectors
;
96 assert (IS_ALIGNED (region
->start
, SECTOR_SIZE
));
98 start_sector
= region
->start
/ SECTOR_SIZE
;
99 nr_sectors
= DIV_ROUND_UP (region
->len
, SECTOR_SIZE
);
101 assert (start_sector
<= UINT32_MAX
);
102 assert (nr_sectors
<= UINT32_MAX
);
104 out
[0] = bootable
? 0x80 : 0;
105 chs_too_large (&out
[1]);
106 out
[4] = partition_id
;
107 chs_too_large (&out
[5]);
108 u32
= htole32 (start_sector
);
109 memcpy (&out
[8], &u32
, 4);
110 u32
= htole32 (nr_sectors
);
111 memcpy (&out
[12], &u32
, 4);
115 create_gpt_protective_mbr (struct virtual_disk
*disk
, unsigned char *out
)
117 struct region region
;
120 /* Protective MBR creates an MBR partition with partition ID 0xee
121 * which covers the whole of the disk, or as much of the disk as
122 * expressible with MBR.
125 end
= virtual_size (&disk
->regions
) - 1;
126 if (end
> UINT32_MAX
* SECTOR_SIZE
)
127 end
= UINT32_MAX
* SECTOR_SIZE
;
129 region
.len
= region
.end
- region
.start
+ 1;
131 create_mbr_partition_table_entry (®ion
, false, 0xee, &out
[0x1be]);
133 /* Boot sector signature. */
139 create_gpt_partition_header (struct virtual_disk
*disk
,
140 const void *pt
, bool is_primary
,
144 struct gpt_header
*header
= (struct gpt_header
*) out
;
146 nr_lbas
= virtual_size (&disk
->regions
) / SECTOR_SIZE
;
148 memset (header
, 0, sizeof *header
);
149 memcpy (header
->signature
, GPT_SIGNATURE
, sizeof (header
->signature
));
150 memcpy (header
->revision
, GPT_REVISION
, sizeof (header
->revision
));
151 header
->header_size
= htole32 (sizeof *header
);
153 header
->current_lba
= htole64 (1);
154 header
->backup_lba
= htole64 (nr_lbas
- 1);
157 header
->current_lba
= htole64 (nr_lbas
- 1);
158 header
->backup_lba
= htole64 (1);
160 header
->first_usable_lba
= htole64 (34);
161 header
->last_usable_lba
= htole64 (nr_lbas
- 34);
163 header
->partition_entries_lba
= htole64 (2);
165 header
->partition_entries_lba
= htole64 (nr_lbas
- 33);
166 header
->nr_partition_entries
= htole32 (GPT_MIN_PARTITIONS
);
167 header
->size_partition_entry
= htole32 (GPT_PT_ENTRY_SIZE
);
168 header
->crc_partitions
=
169 htole32 (efi_crc32 (pt
, GPT_PT_ENTRY_SIZE
* GPT_MIN_PARTITIONS
));
171 /* Must be computed last. */
172 header
->crc
= htole32 (efi_crc32 (header
, sizeof *header
));
176 create_gpt_partition_table_entry (const struct region
*region
,
178 char partition_type_guid
[16],
182 struct gpt_entry
*entry
= (struct gpt_entry
*) out
;
184 assert (sizeof (struct gpt_entry
) == GPT_PT_ENTRY_SIZE
);
186 memcpy (entry
->partition_type_guid
, partition_type_guid
, 16);
187 memcpy (entry
->unique_guid
, guid
, 16);
189 entry
->first_lba
= htole64 (region
->start
/ SECTOR_SIZE
);
190 entry
->last_lba
= htole64 (region
->end
/ SECTOR_SIZE
);
191 entry
->attributes
= htole64 (bootable
? 4 : 0);
195 create_gpt_partition_table (struct virtual_disk
*disk
, unsigned char *out
)
199 for (j
= 0; j
< nr_regions (&disk
->regions
); ++j
) {
200 const struct region
*region
= get_region (&disk
->regions
, j
);
202 /* Find the (only) partition region, which has type region_file. */
203 if (region
->type
== region_file
) {
204 create_gpt_partition_table_entry (region
, true,
208 out
+= GPT_PT_ENTRY_SIZE
;