1 |
|
|
/* $OpenBSD: cd9660_eltorito.c,v 1.13 2017/11/07 00:22:40 yasuoka Exp $ */ |
2 |
|
|
/* $NetBSD: cd9660_eltorito.c,v 1.20 2013/01/28 21:03:28 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan |
6 |
|
|
* Perez-Rathke and Ram Vedam. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, |
9 |
|
|
* Alan Perez-Rathke and Ram Vedam. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or |
12 |
|
|
* without modification, are permitted provided that the following |
13 |
|
|
* conditions are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above |
17 |
|
|
* copyright notice, this list of conditions and the following |
18 |
|
|
* disclaimer in the documentation and/or other materials provided |
19 |
|
|
* with the distribution. |
20 |
|
|
* |
21 |
|
|
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN |
22 |
|
|
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR |
23 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
24 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
25 |
|
|
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN |
26 |
|
|
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, |
27 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
28 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
29 |
|
|
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
30 |
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
31 |
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
33 |
|
|
* OF SUCH DAMAGE. |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
|
37 |
|
|
#include "cd9660.h" |
38 |
|
|
#include "cd9660_eltorito.h" |
39 |
|
|
#include <inttypes.h> |
40 |
|
|
|
41 |
|
|
/* |
42 |
|
|
* Partition Status Information from Apple Tech Note 1189 |
43 |
|
|
*/ |
44 |
|
|
#define APPLE_PS_VALID 0x00000001 /* Entry is valid */ |
45 |
|
|
#define APPLE_PS_ALLOCATED 0x00000002 /* Entry is allocated */ |
46 |
|
|
#define APPLE_PS_READABLE 0x00000010 /* Entry is readable */ |
47 |
|
|
#define APPLE_PS_WRITABLE 0x00000020 /* Entry is writable */ |
48 |
|
|
|
49 |
|
|
#ifdef DEBUG |
50 |
|
|
#define ELTORITO_DPRINTF(__x) printf __x |
51 |
|
|
#else |
52 |
|
|
#define ELTORITO_DPRINTF(__x) |
53 |
|
|
#endif |
54 |
|
|
|
55 |
|
|
static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void); |
56 |
|
|
static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); |
57 |
|
|
static struct boot_catalog_entry *cd9660_boot_setup_default_entry( |
58 |
|
|
struct cd9660_boot_image *); |
59 |
|
|
static struct boot_catalog_entry *cd9660_boot_setup_section_head(char); |
60 |
|
|
static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); |
61 |
|
|
#if 0 |
62 |
|
|
static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *); |
63 |
|
|
#endif |
64 |
|
|
|
65 |
|
|
int |
66 |
|
|
cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info) |
67 |
|
|
{ |
68 |
|
|
struct stat stbuf; |
69 |
|
|
const char *mode_msg; |
70 |
|
|
char *temp; |
71 |
|
|
char *sysname; |
72 |
|
|
char *filename; |
73 |
|
|
struct cd9660_boot_image *new_image, *tmp_image; |
74 |
|
|
|
75 |
|
|
assert(boot_info != NULL); |
76 |
|
|
|
77 |
|
|
if (*boot_info == '\0') { |
78 |
|
|
warnx("Error: Boot disk information must be in the " |
79 |
|
|
"format 'system;filename'"); |
80 |
|
|
return 0; |
81 |
|
|
} |
82 |
|
|
|
83 |
|
|
/* First decode the boot information */ |
84 |
|
|
temp = estrdup(boot_info); |
85 |
|
|
|
86 |
|
|
sysname = temp; |
87 |
|
|
filename = strchr(sysname, ';'); |
88 |
|
|
if (filename == NULL) { |
89 |
|
|
warnx("supply boot disk information in the format " |
90 |
|
|
"'system;filename'"); |
91 |
|
|
free(temp); |
92 |
|
|
return 0; |
93 |
|
|
} |
94 |
|
|
|
95 |
|
|
*filename++ = '\0'; |
96 |
|
|
|
97 |
|
|
new_image = ecalloc(1, sizeof(*new_image)); |
98 |
|
|
new_image->loadSegment = 0; /* default for now */ |
99 |
|
|
|
100 |
|
|
/* Decode System */ |
101 |
|
|
if (strcmp(sysname, "i386") == 0) |
102 |
|
|
new_image->system = ET_SYS_X86; |
103 |
|
|
else if (strcmp(sysname, "powerpc") == 0) |
104 |
|
|
new_image->system = ET_SYS_PPC; |
105 |
|
|
else if (strcmp(sysname, "macppc") == 0) |
106 |
|
|
new_image->system = ET_SYS_MAC; |
107 |
|
|
else if (strcmp(sysname, "efi") == 0) |
108 |
|
|
new_image->system = ET_SYS_EFI; |
109 |
|
|
else { |
110 |
|
|
warnx("boot disk system must be " |
111 |
|
|
"i386, macppc, powerpc, or efi"); |
112 |
|
|
free(temp); |
113 |
|
|
free(new_image); |
114 |
|
|
return 0; |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
|
118 |
|
|
new_image->filename = estrdup(filename); |
119 |
|
|
|
120 |
|
|
free(temp); |
121 |
|
|
|
122 |
|
|
/* Get information about the file */ |
123 |
|
|
if (lstat(new_image->filename, &stbuf) == -1) |
124 |
|
|
err(1, "%s: lstat(\"%s\")", __func__, new_image->filename); |
125 |
|
|
|
126 |
|
|
switch (stbuf.st_size) { |
127 |
|
|
case 1440 * 1024: |
128 |
|
|
new_image->targetMode = ET_MEDIA_144FDD; |
129 |
|
|
mode_msg = "Assigned boot image to 1.44 emulation mode"; |
130 |
|
|
break; |
131 |
|
|
case 1200 * 1024: |
132 |
|
|
new_image->targetMode = ET_MEDIA_12FDD; |
133 |
|
|
mode_msg = "Assigned boot image to 1.2 emulation mode"; |
134 |
|
|
break; |
135 |
|
|
case 2880 * 1024: |
136 |
|
|
new_image->targetMode = ET_MEDIA_288FDD; |
137 |
|
|
mode_msg = "Assigned boot image to 2.88 emulation mode"; |
138 |
|
|
break; |
139 |
|
|
default: |
140 |
|
|
new_image->targetMode = ET_MEDIA_NOEM; |
141 |
|
|
mode_msg = "Assigned boot image to no emulation mode"; |
142 |
|
|
break; |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
new_image->size = stbuf.st_size; |
146 |
|
|
new_image->num_sectors = |
147 |
|
|
howmany(new_image->size, diskStructure->sectorSize) * |
148 |
|
|
howmany(diskStructure->sectorSize, 512); |
149 |
|
|
new_image->sector = -1; |
150 |
|
|
/* Bootable by default */ |
151 |
|
|
new_image->bootable = ET_BOOTABLE; |
152 |
|
|
/* Add boot disk */ |
153 |
|
|
|
154 |
|
|
/* Group images for the same platform together. */ |
155 |
|
|
TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) { |
156 |
|
|
if (tmp_image->system != new_image->system) |
157 |
|
|
break; |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
if (tmp_image == NULL) |
161 |
|
|
TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image, |
162 |
|
|
image_list); |
163 |
|
|
else |
164 |
|
|
TAILQ_INSERT_AFTER(&diskStructure->boot_images, tmp_image, |
165 |
|
|
new_image, image_list); |
166 |
|
|
|
167 |
|
|
new_image->serialno = diskStructure->image_serialno++; |
168 |
|
|
|
169 |
|
|
/* TODO : Need to do anything about the boot image in the tree? */ |
170 |
|
|
diskStructure->is_bootable = 1; |
171 |
|
|
|
172 |
|
|
return 1; |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
int |
176 |
|
|
cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure, |
177 |
|
|
const char *option_string, const char *value) |
178 |
|
|
{ |
179 |
|
|
char *eptr; |
180 |
|
|
struct cd9660_boot_image *image; |
181 |
|
|
|
182 |
|
|
assert(option_string != NULL); |
183 |
|
|
|
184 |
|
|
/* Find the last image added */ |
185 |
|
|
TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) { |
186 |
|
|
if (image->serialno + 1 == diskStructure->image_serialno) |
187 |
|
|
break; |
188 |
|
|
} |
189 |
|
|
if (image == NULL) |
190 |
|
|
errx(1, "Attempted to add boot option, " |
191 |
|
|
"but no boot images have been specified"); |
192 |
|
|
|
193 |
|
|
if (strcmp(option_string, "no-emul-boot") == 0) { |
194 |
|
|
image->targetMode = ET_MEDIA_NOEM; |
195 |
|
|
} else if (strcmp(option_string, "no-boot") == 0) { |
196 |
|
|
image->bootable = ET_NOT_BOOTABLE; |
197 |
|
|
} else if (strcmp(option_string, "hard-disk-boot") == 0) { |
198 |
|
|
image->targetMode = ET_MEDIA_HDD; |
199 |
|
|
} else if (strcmp(option_string, "boot-load-segment") == 0) { |
200 |
|
|
image->loadSegment = strtoul(value, &eptr, 16); |
201 |
|
|
if (eptr == value || *eptr != '\0' || errno != ERANGE) { |
202 |
|
|
warn("%s: strtoul", __func__); |
203 |
|
|
return 0; |
204 |
|
|
} |
205 |
|
|
} else { |
206 |
|
|
return 0; |
207 |
|
|
} |
208 |
|
|
return 1; |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
static struct boot_catalog_entry * |
212 |
|
|
cd9660_init_boot_catalog_entry(void) |
213 |
|
|
{ |
214 |
|
|
return ecalloc(1, sizeof(struct boot_catalog_entry)); |
215 |
|
|
} |
216 |
|
|
|
217 |
|
|
static struct boot_catalog_entry * |
218 |
|
|
cd9660_boot_setup_validation_entry(char sys) |
219 |
|
|
{ |
220 |
|
|
struct boot_catalog_entry *entry; |
221 |
|
|
boot_catalog_validation_entry *ve; |
222 |
|
|
int16_t checksum; |
223 |
|
|
unsigned char *csptr; |
224 |
|
|
size_t i; |
225 |
|
|
entry = cd9660_init_boot_catalog_entry(); |
226 |
|
|
|
227 |
|
|
entry->entry_type = ET_ENTRY_VE; |
228 |
|
|
ve = &entry->entry_data.VE; |
229 |
|
|
|
230 |
|
|
ve->header_id[0] = 1; |
231 |
|
|
ve->platform_id[0] = sys; |
232 |
|
|
ve->key[0] = 0x55; |
233 |
|
|
ve->key[1] = 0xAA; |
234 |
|
|
|
235 |
|
|
/* Calculate checksum */ |
236 |
|
|
checksum = 0; |
237 |
|
|
cd9660_721(0, ve->checksum); |
238 |
|
|
csptr = (unsigned char*)ve; |
239 |
|
|
for (i = 0; i < sizeof(*ve); i += 2) { |
240 |
|
|
checksum += (int16_t)csptr[i]; |
241 |
|
|
checksum += 256 * (int16_t)csptr[i + 1]; |
242 |
|
|
} |
243 |
|
|
checksum = -checksum; |
244 |
|
|
cd9660_721(checksum, ve->checksum); |
245 |
|
|
|
246 |
|
|
ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, " |
247 |
|
|
"checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0], |
248 |
|
|
ve->key[0], ve->key[1], checksum)); |
249 |
|
|
return entry; |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
static struct boot_catalog_entry * |
253 |
|
|
cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk) |
254 |
|
|
{ |
255 |
|
|
struct boot_catalog_entry *default_entry; |
256 |
|
|
boot_catalog_initial_entry *ie; |
257 |
|
|
|
258 |
|
|
default_entry = cd9660_init_boot_catalog_entry(); |
259 |
|
|
if (default_entry == NULL) |
260 |
|
|
return NULL; |
261 |
|
|
|
262 |
|
|
default_entry->entry_type = ET_ENTRY_IE; |
263 |
|
|
ie = &default_entry->entry_data.IE; |
264 |
|
|
|
265 |
|
|
ie->boot_indicator[0] = disk->bootable; |
266 |
|
|
ie->media_type[0] = disk->targetMode; |
267 |
|
|
cd9660_721(disk->loadSegment, ie->load_segment); |
268 |
|
|
ie->system_type[0] = disk->system; |
269 |
|
|
cd9660_721(disk->num_sectors, ie->sector_count); |
270 |
|
|
cd9660_731(disk->sector, ie->load_rba); |
271 |
|
|
|
272 |
|
|
ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, " |
273 |
|
|
"load segment %04x, system type %d, sector count %d, " |
274 |
|
|
"load rba %d\n", __func__, ie->boot_indicator[0], |
275 |
|
|
ie->media_type[0], disk->loadSegment, ie->system_type[0], |
276 |
|
|
disk->num_sectors, disk->sector)); |
277 |
|
|
return default_entry; |
278 |
|
|
} |
279 |
|
|
|
280 |
|
|
static struct boot_catalog_entry * |
281 |
|
|
cd9660_boot_setup_section_head(char platform) |
282 |
|
|
{ |
283 |
|
|
struct boot_catalog_entry *entry; |
284 |
|
|
boot_catalog_section_header *sh; |
285 |
|
|
|
286 |
|
|
entry = cd9660_init_boot_catalog_entry(); |
287 |
|
|
if (entry == NULL) |
288 |
|
|
return NULL; |
289 |
|
|
|
290 |
|
|
entry->entry_type = ET_ENTRY_SH; |
291 |
|
|
sh = &entry->entry_data.SH; |
292 |
|
|
/* More by default. The last one will manually be set to 0x91 */ |
293 |
|
|
sh->header_indicator[0] = ET_SECTION_HEADER_MORE; |
294 |
|
|
sh->platform_id[0] = platform; |
295 |
|
|
sh->num_section_entries[0] = 0; |
296 |
|
|
return entry; |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
static struct boot_catalog_entry * |
300 |
|
|
cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk) |
301 |
|
|
{ |
302 |
|
|
struct boot_catalog_entry *entry; |
303 |
|
|
boot_catalog_section_entry *se; |
304 |
|
|
if ((entry = cd9660_init_boot_catalog_entry()) == NULL) |
305 |
|
|
return NULL; |
306 |
|
|
|
307 |
|
|
entry->entry_type = ET_ENTRY_SE; |
308 |
|
|
se = &entry->entry_data.SE; |
309 |
|
|
|
310 |
|
|
se->boot_indicator[0] = ET_BOOTABLE; |
311 |
|
|
se->media_type[0] = disk->targetMode; |
312 |
|
|
cd9660_721(disk->loadSegment, se->load_segment); |
313 |
|
|
cd9660_721(disk->num_sectors, se->sector_count); |
314 |
|
|
cd9660_731(disk->sector, se->load_rba); |
315 |
|
|
return entry; |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
#if 0 |
319 |
|
|
static u_char |
320 |
|
|
cd9660_boot_get_system_type(struct cd9660_boot_image *disk) |
321 |
|
|
{ |
322 |
|
|
/* |
323 |
|
|
For hard drive booting, we need to examine the MBR to figure |
324 |
|
|
out what the partition type is |
325 |
|
|
*/ |
326 |
|
|
return 0; |
327 |
|
|
} |
328 |
|
|
#endif |
329 |
|
|
|
330 |
|
|
/* |
331 |
|
|
* Set up the BVD, Boot catalog, and the boot entries, but do no writing |
332 |
|
|
*/ |
333 |
|
|
int |
334 |
|
|
cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector) |
335 |
|
|
{ |
336 |
|
|
int sector; |
337 |
|
|
int used_sectors; |
338 |
|
|
int num_entries = 0; |
339 |
|
|
int catalog_sectors; |
340 |
|
|
struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, *efi_head, |
341 |
|
|
*valid_entry, *default_entry, *temp, *head, **headp, *next; |
342 |
|
|
struct cd9660_boot_image *tmp_disk; |
343 |
|
|
|
344 |
|
|
headp = NULL; |
345 |
|
|
x86_head = mac_head = ppc_head = efi_head = NULL; |
346 |
|
|
|
347 |
|
|
/* If there are no boot disks, don't bother building boot information */ |
348 |
|
|
if (TAILQ_EMPTY(&diskStructure->boot_images)) |
349 |
|
|
return 0; |
350 |
|
|
|
351 |
|
|
/* Point to catalog: For now assume it consumes one sector */ |
352 |
|
|
ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector)); |
353 |
|
|
diskStructure->boot_catalog_sector = first_sector; |
354 |
|
|
cd9660_bothendian_dword(first_sector, |
355 |
|
|
diskStructure->boot_descriptor->boot_catalog_pointer); |
356 |
|
|
|
357 |
|
|
/* Step 1: Generate boot catalog */ |
358 |
|
|
/* Step 1a: Validation entry */ |
359 |
|
|
valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86); |
360 |
|
|
if (valid_entry == NULL) |
361 |
|
|
return -1; |
362 |
|
|
|
363 |
|
|
/* |
364 |
|
|
* Count how many boot images there are, |
365 |
|
|
* and how many sectors they consume. |
366 |
|
|
*/ |
367 |
|
|
num_entries = 1; |
368 |
|
|
used_sectors = 0; |
369 |
|
|
|
370 |
|
|
TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) { |
371 |
|
|
used_sectors += tmp_disk->num_sectors; |
372 |
|
|
|
373 |
|
|
/* One default entry per image */ |
374 |
|
|
num_entries++; |
375 |
|
|
} |
376 |
|
|
catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize); |
377 |
|
|
used_sectors += catalog_sectors; |
378 |
|
|
|
379 |
|
|
/* Populate sector numbers */ |
380 |
|
|
sector = first_sector + catalog_sectors; |
381 |
|
|
TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) { |
382 |
|
|
tmp_disk->sector = sector; |
383 |
|
|
sector += tmp_disk->num_sectors; |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct); |
387 |
|
|
|
388 |
|
|
/* Step 1b: Initial/default entry */ |
389 |
|
|
/* TODO : PARAM */ |
390 |
|
|
tmp_disk = TAILQ_FIRST(&diskStructure->boot_images); |
391 |
|
|
default_entry = cd9660_boot_setup_default_entry(tmp_disk); |
392 |
|
|
if (default_entry == NULL) { |
393 |
|
|
warnx("Error: memory allocation failed in cd9660_setup_boot"); |
394 |
|
|
return -1; |
395 |
|
|
} |
396 |
|
|
|
397 |
|
|
LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct); |
398 |
|
|
|
399 |
|
|
/* Todo: multiple default entries? */ |
400 |
|
|
|
401 |
|
|
tmp_disk = TAILQ_NEXT(tmp_disk, image_list); |
402 |
|
|
|
403 |
|
|
temp = default_entry; |
404 |
|
|
|
405 |
|
|
/* If multiple boot images are given : */ |
406 |
|
|
while (tmp_disk != NULL) { |
407 |
|
|
/* Step 2: Section header */ |
408 |
|
|
switch (tmp_disk->system) { |
409 |
|
|
case ET_SYS_X86: |
410 |
|
|
headp = &x86_head; |
411 |
|
|
break; |
412 |
|
|
case ET_SYS_PPC: |
413 |
|
|
headp = &ppc_head; |
414 |
|
|
break; |
415 |
|
|
case ET_SYS_MAC: |
416 |
|
|
headp = &mac_head; |
417 |
|
|
break; |
418 |
|
|
case ET_SYS_EFI: |
419 |
|
|
headp = &efi_head; |
420 |
|
|
break; |
421 |
|
|
default: |
422 |
|
|
warnx("%s: internal error: unknown system type", |
423 |
|
|
__func__); |
424 |
|
|
return -1; |
425 |
|
|
} |
426 |
|
|
|
427 |
|
|
if (*headp == NULL) { |
428 |
|
|
head = |
429 |
|
|
cd9660_boot_setup_section_head(tmp_disk->system); |
430 |
|
|
if (head == NULL) { |
431 |
|
|
warnx("Error: memory allocation failed in " |
432 |
|
|
"cd9660_setup_boot"); |
433 |
|
|
return -1; |
434 |
|
|
} |
435 |
|
|
LIST_INSERT_AFTER(default_entry, head, ll_struct); |
436 |
|
|
*headp = head; |
437 |
|
|
} else |
438 |
|
|
head = *headp; |
439 |
|
|
|
440 |
|
|
head->entry_data.SH.num_section_entries[0]++; |
441 |
|
|
|
442 |
|
|
/* Step 2a: Section entry and extensions */ |
443 |
|
|
temp = cd9660_boot_setup_section_entry(tmp_disk); |
444 |
|
|
if (temp == NULL) { |
445 |
|
|
warn("%s: cd9660_boot_setup_section_entry", __func__); |
446 |
|
|
return -1; |
447 |
|
|
} |
448 |
|
|
|
449 |
|
|
while ((next = LIST_NEXT(head, ll_struct)) != NULL && |
450 |
|
|
next->entry_type == ET_ENTRY_SE) |
451 |
|
|
head = next; |
452 |
|
|
|
453 |
|
|
LIST_INSERT_AFTER(head, temp, ll_struct); |
454 |
|
|
tmp_disk = TAILQ_NEXT(tmp_disk, image_list); |
455 |
|
|
} |
456 |
|
|
|
457 |
|
|
/* TODO: Remaining boot disks when implemented */ |
458 |
|
|
|
459 |
|
|
return first_sector + used_sectors; |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
int |
463 |
|
|
cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure, |
464 |
|
|
volume_descriptor *bvd) |
465 |
|
|
{ |
466 |
|
|
boot_volume_descriptor *bvdData = |
467 |
|
|
(boot_volume_descriptor*)bvd->volumeDescriptorData; |
468 |
|
|
|
469 |
|
|
bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT; |
470 |
|
|
memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); |
471 |
|
|
bvdData->version[0] = 1; |
472 |
|
|
memcpy(bvdData->boot_system_identifier, ET_ID, 23); |
473 |
|
|
memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); |
474 |
|
|
diskStructure->boot_descriptor = |
475 |
|
|
(boot_volume_descriptor*) bvd->volumeDescriptorData; |
476 |
|
|
return 1; |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
static int |
480 |
|
|
cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start, |
481 |
|
|
off_t nsectors, int type) |
482 |
|
|
{ |
483 |
|
|
uint8_t val; |
484 |
|
|
uint32_t lba; |
485 |
|
|
|
486 |
|
|
if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1) |
487 |
|
|
err(1, "fseeko"); |
488 |
|
|
|
489 |
|
|
val = 0x80; /* Bootable */ |
490 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
491 |
|
|
|
492 |
|
|
val = 0xff; /* CHS begin */ |
493 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
494 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
495 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
496 |
|
|
|
497 |
|
|
val = type; /* Part type */ |
498 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
499 |
|
|
|
500 |
|
|
val = 0xff; /* CHS end */ |
501 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
502 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
503 |
|
|
fwrite(&val, sizeof(val), 1, fd); |
504 |
|
|
|
505 |
|
|
/* LBA extent */ |
506 |
|
|
lba = htole32(sector_start); |
507 |
|
|
fwrite(&lba, sizeof(lba), 1, fd); |
508 |
|
|
lba = htole32(nsectors); |
509 |
|
|
fwrite(&lba, sizeof(lba), 1, fd); |
510 |
|
|
|
511 |
|
|
return 0; |
512 |
|
|
} |
513 |
|
|
|
514 |
|
|
static int |
515 |
|
|
cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions, |
516 |
|
|
off_t sector_start, off_t nsectors, off_t sector_size, |
517 |
|
|
const char *part_name, const char *part_type) |
518 |
|
|
{ |
519 |
|
|
uint32_t apm32, part_status; |
520 |
|
|
uint16_t apm16; |
521 |
|
|
|
522 |
|
|
part_status = APPLE_PS_VALID | APPLE_PS_ALLOCATED | APPLE_PS_READABLE | |
523 |
|
|
APPLE_PS_WRITABLE; |
524 |
|
|
|
525 |
|
|
if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1) |
526 |
|
|
err(1, "fseeko"); |
527 |
|
|
|
528 |
|
|
/* Signature */ |
529 |
|
|
apm16 = htobe16(0x504d); |
530 |
|
|
fwrite(&apm16, sizeof(apm16), 1, fd); |
531 |
|
|
apm16 = 0; |
532 |
|
|
fwrite(&apm16, sizeof(apm16), 1, fd); |
533 |
|
|
|
534 |
|
|
/* Total number of partitions */ |
535 |
|
|
apm32 = htobe32(total_partitions); |
536 |
|
|
fwrite(&apm32, sizeof(apm32), 1, fd); |
537 |
|
|
/* Bounds */ |
538 |
|
|
apm32 = htobe32(sector_start); |
539 |
|
|
fwrite(&apm32, sizeof(apm32), 1, fd); |
540 |
|
|
apm32 = htobe32(nsectors); |
541 |
|
|
fwrite(&apm32, sizeof(apm32), 1, fd); |
542 |
|
|
|
543 |
|
|
fwrite(part_name, strlen(part_name) + 1, 1, fd); |
544 |
|
|
fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR); |
545 |
|
|
fwrite(part_type, strlen(part_type) + 1, 1, fd); |
546 |
|
|
fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR); |
547 |
|
|
|
548 |
|
|
apm32 = 0; |
549 |
|
|
/* pmLgDataStart */ |
550 |
|
|
fwrite(&apm32, sizeof(apm32), 1, fd); |
551 |
|
|
/* pmDataCnt */ |
552 |
|
|
apm32 = htobe32(nsectors); |
553 |
|
|
fwrite(&apm32, sizeof(apm32), 1, fd); |
554 |
|
|
/* pmPartStatus */ |
555 |
|
|
apm32 = htobe32(part_status); |
556 |
|
|
fwrite(&apm32, sizeof(apm32), 1, fd); |
557 |
|
|
|
558 |
|
|
return 0; |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
int |
562 |
|
|
cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd) |
563 |
|
|
{ |
564 |
|
|
struct boot_catalog_entry *e; |
565 |
|
|
struct cd9660_boot_image *t; |
566 |
|
|
int apm_partitions = 0; |
567 |
|
|
int mbr_partitions = 0; |
568 |
|
|
|
569 |
|
|
/* write boot catalog */ |
570 |
|
|
if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector * |
571 |
|
|
diskStructure->sectorSize, SEEK_SET) == -1) |
572 |
|
|
err(1, "fseeko"); |
573 |
|
|
|
574 |
|
|
LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) { |
575 |
|
|
/* |
576 |
|
|
* It doesnt matter which one gets written |
577 |
|
|
* since they are the same size |
578 |
|
|
*/ |
579 |
|
|
fwrite(&(e->entry_data.VE), 1, 32, fd); |
580 |
|
|
} |
581 |
|
|
|
582 |
|
|
/* copy boot images */ |
583 |
|
|
TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) { |
584 |
|
|
cd9660_copy_file(diskStructure, fd, t->sector, t->filename); |
585 |
|
|
|
586 |
|
|
if (t->system == ET_SYS_MAC) |
587 |
|
|
apm_partitions++; |
588 |
|
|
if (t->system == ET_SYS_PPC) |
589 |
|
|
mbr_partitions++; |
590 |
|
|
} |
591 |
|
|
|
592 |
|
|
/* some systems need partition tables as well */ |
593 |
|
|
if (mbr_partitions > 0) { |
594 |
|
|
uint16_t sig; |
595 |
|
|
|
596 |
|
|
fseek(fd, 0x1fe, SEEK_SET); |
597 |
|
|
sig = htole16(0xaa55); |
598 |
|
|
fwrite(&sig, sizeof(sig), 1, fd); |
599 |
|
|
|
600 |
|
|
mbr_partitions = 0; |
601 |
|
|
|
602 |
|
|
/* Write all partition entries */ |
603 |
|
|
TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) { |
604 |
|
|
if (t->system != ET_SYS_PPC) |
605 |
|
|
continue; |
606 |
|
|
cd9660_write_mbr_partition_entry(fd, mbr_partitions++, |
607 |
|
|
t->sector * (diskStructure->sectorSize / 512), |
608 |
|
|
t->num_sectors * (diskStructure->sectorSize / 512), |
609 |
|
|
0x41 /* PReP Boot */); |
610 |
|
|
} |
611 |
|
|
} |
612 |
|
|
|
613 |
|
|
if (apm_partitions > 0) { |
614 |
|
|
/* Write DDR and global APM info */ |
615 |
|
|
uint32_t apm32; |
616 |
|
|
uint16_t apm16; |
617 |
|
|
int total_parts; |
618 |
|
|
|
619 |
|
|
fseek(fd, 0, SEEK_SET); |
620 |
|
|
apm16 = htobe16(0x4552); |
621 |
|
|
fwrite(&apm16, sizeof(apm16), 1, fd); |
622 |
|
|
/* Device block size */ |
623 |
|
|
apm16 = htobe16(512); |
624 |
|
|
fwrite(&apm16, sizeof(apm16), 1, fd); |
625 |
|
|
/* Device block count */ |
626 |
|
|
apm32 = htobe32(diskStructure->totalSectors * |
627 |
|
|
(diskStructure->sectorSize / 512)); |
628 |
|
|
fwrite(&apm32, sizeof(apm32), 1, fd); |
629 |
|
|
/* Device type/id */ |
630 |
|
|
apm16 = htobe16(1); |
631 |
|
|
fwrite(&apm16, sizeof(apm16), 1, fd); |
632 |
|
|
fwrite(&apm16, sizeof(apm16), 1, fd); |
633 |
|
|
|
634 |
|
|
/* Count total needed entries */ |
635 |
|
|
total_parts = 2 + apm_partitions; /* Self + ISO9660 */ |
636 |
|
|
|
637 |
|
|
/* Write self-descriptor */ |
638 |
|
|
cd9660_write_apm_partition_entry(fd, 0, total_parts, 1, |
639 |
|
|
total_parts, 512, "Apple", "Apple_partition_map"); |
640 |
|
|
|
641 |
|
|
/* Write all partition entries */ |
642 |
|
|
apm_partitions = 0; |
643 |
|
|
TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) { |
644 |
|
|
if (t->system != ET_SYS_MAC) |
645 |
|
|
continue; |
646 |
|
|
|
647 |
|
|
cd9660_write_apm_partition_entry(fd, |
648 |
|
|
1 + apm_partitions++, total_parts, |
649 |
|
|
t->sector * (diskStructure->sectorSize / 512), |
650 |
|
|
t->num_sectors * (diskStructure->sectorSize / 512), |
651 |
|
|
512, "CD Boot", "Apple_Bootstrap"); |
652 |
|
|
} |
653 |
|
|
|
654 |
|
|
/* Write ISO9660 descriptor, enclosing the whole disk */ |
655 |
|
|
cd9660_write_apm_partition_entry(fd, 2 + apm_partitions, |
656 |
|
|
total_parts, 0, diskStructure->totalSectors * |
657 |
|
|
(diskStructure->sectorSize / 512), 512, "ISO9660", |
658 |
|
|
"CD_ROM_Mode_1"); |
659 |
|
|
} |
660 |
|
|
|
661 |
|
|
return 0; |
662 |
|
|
} |