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
42 #include <nbdkit-plugin.h>
44 #include "byte-swapping.h"
46 #include "isaligned.h"
50 #include "virtual-disk.h"
52 static const struct region
*find_file_region (size_t i
, size_t *j
);
53 static const struct region
*find_ebr_region (size_t i
, size_t *j
);
55 /* Create the MBR and optionally EBRs. */
57 create_mbr_layout (void)
62 primary
[0x1fe] = 0x55;
63 primary
[0x1ff] = 0xaa;
65 if (the_files
.len
<= 4) {
66 /* Basic MBR with no extended partition. */
67 for (i
= 0; i
< the_files
.len
; ++i
) {
68 const struct region
*region
= find_file_region (i
, &j
);
70 create_mbr_partition_table_entry (region
, i
== 0, the_files
.ptr
[i
].mbr_id
,
71 &primary
[0x1be + 16*i
]);
76 const struct region
*rptr
, *eptr0
, *eptr
;
78 /* The first three primary partitions correspond to the first
81 for (i
= 0; i
< 3; ++i
) {
82 rptr
= find_file_region (i
, &j
);
83 create_mbr_partition_table_entry (rptr
, i
== 0, the_files
.ptr
[i
].mbr_id
,
84 &primary
[0x1be + 16*i
]);
87 /* The fourth partition is an extended PTE and does not correspond
88 * to any file. This partition starts with the first EBR, so find
89 * it. The partition extends to the end of the disk.
91 eptr0
= find_ebr_region (3, &j
);
92 region
.start
= eptr0
->start
;
93 region
.end
= virtual_size (&the_regions
) - 1; /* to end of disk */
94 region
.len
= region
.end
- region
.start
+ 1;
95 create_mbr_partition_table_entry (®ion
, false, 0xf, &primary
[0x1ee]);
97 /* The remaining files are mapped to logical partitions living in
98 * the fourth extended partition.
100 for (i
= 3; i
< the_files
.len
; ++i
) {
104 eptr
= find_ebr_region (i
, &j
);
105 rptr
= find_file_region (i
, &j
);
108 ebr
[i
-3][0x1fe] = 0x55;
109 ebr
[i
-3][0x1ff] = 0xaa;
111 /* First entry in EBR contains:
112 * offset from EBR sector to the first sector of the logical partition
113 * total count of sectors in the logical partition
115 region
.start
= rptr
->start
- eptr
->start
;
116 region
.len
= rptr
->len
;
117 create_mbr_partition_table_entry (®ion
, false, the_files
.ptr
[i
].mbr_id
,
120 if (i
< the_files
.len
-1) {
122 const struct region
*enext
= find_ebr_region (i
+1, &j2
);
123 const struct region
*rnext
= find_file_region (i
+1, &j2
);
125 /* Second entry in the EBR contains:
126 * address of next EBR relative to extended partition
127 * total count of sectors in the next logical partition including
130 region
.start
= enext
->start
- eptr0
->start
;
131 region
.len
= rnext
->end
- enext
->start
+ 1;
132 create_mbr_partition_table_entry (®ion
, false, 0xf,
139 /* Find the region corresponding to file[i].
140 * j is a scratch register ensuring we only do a linear scan.
142 static const struct region
*
143 find_file_region (size_t i
, size_t *j
)
145 const struct region
*region
;
147 for (; *j
< nr_regions (&the_regions
); ++(*j
)) {
148 region
= &the_regions
.ptr
[*j
];
149 if (region
->type
== region_file
&& region
->u
.i
== i
)
155 /* Find the region corresponding to EBR of file[i] (i >= 3).
156 * j is a scratch register ensuring we only do a linear scan.
158 static const struct region
*
159 find_ebr_region (size_t i
, size_t *j
)
161 const struct region
*region
;
165 for (; *j
< nr_regions (&the_regions
); ++(*j
)) {
166 region
= &the_regions
.ptr
[*j
];
167 if (region
->type
== region_data
&& region
->u
.data
== ebr
[i
-3])
174 chs_too_large (unsigned char *out
)
176 const int c
= 1023, h
= 254, s
= 63;
179 out
[1] = (c
& 0x300) >> 2 | s
;
184 create_mbr_partition_table_entry (const struct region
*region
,
185 bool bootable
, int partition_id
,
188 uint64_t start_sector
, nr_sectors
;
191 assert (IS_ALIGNED (region
->start
, SECTOR_SIZE
));
193 start_sector
= region
->start
/ SECTOR_SIZE
;
194 nr_sectors
= DIV_ROUND_UP (region
->len
, SECTOR_SIZE
);
196 /* The total_size test in partitioning_config_complete should catch
199 assert (start_sector
<= UINT32_MAX
);
200 assert (nr_sectors
<= UINT32_MAX
);
202 out
[0] = bootable
? 0x80 : 0;
203 chs_too_large (&out
[1]);
204 out
[4] = partition_id
;
205 chs_too_large (&out
[5]);
206 u32
= htole32 (start_sector
);
207 memcpy (&out
[8], &u32
, 4);
208 u32
= htole32 (nr_sectors
);
209 memcpy (&out
[12], &u32
, 4);