1 /* @(#)boot.c 1.28 16/10/23 Copyright 1999-2016 J. Schilling */
2 #include <schily/mconfig.h>
4 static UConst
char sccsid
[] =
5 "@(#)boot.c 1.28 16/10/23 Copyright 1999-2016 J. Schilling";
8 * Support for generic boot (sector 0..16)
9 * and to boot Sun sparc and Sun x86 systems.
11 * Copyright (c) 1999-2016 J. Schilling
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2
16 * as published by the Free Software Foundation.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along with
24 * this program; see the file COPYING. If not, write to the Free Software
25 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 #include <schily/fcntl.h>
30 #include <schily/utypes.h>
31 #include <schily/intcvt.h>
32 #include <schily/schily.h>
35 extern int use_sunx86boot
;
37 LOCAL
struct sun_label cd_label
;
38 LOCAL
struct x86_label sx86_label
;
39 LOCAL
struct pc_part fdisk_part
;
40 LOCAL
char *boot_files
[NDKMAP
]; /* Change this for > 8 x86 parts */
42 LOCAL
void init_sparc_label
__PR((void));
43 LOCAL
void init_sunx86_label
__PR((void));
44 EXPORT
int sparc_boot_label
__PR((char *label
));
45 EXPORT
int sunx86_boot_label
__PR((char *label
));
46 EXPORT
int scan_sparc_boot
__PR((char *files
));
47 EXPORT
int scan_sunx86_boot
__PR((char *files
));
48 EXPORT
int make_sun_label
__PR((void));
49 EXPORT
int make_sunx86_label
__PR((void));
50 LOCAL
void dup_sun_label
__PR((int part
));
51 LOCAL
int sunboot_write
__PR((FILE *outfile
));
52 LOCAL
int sunlabel_size
__PR((UInt32_t starting_extent
));
53 LOCAL
int sunlabel_write
__PR((FILE *outfile
));
54 LOCAL
int genboot_size
__PR((UInt32_t starting_extent
));
55 LOCAL
int genboot_write
__PR((FILE *outfile
));
58 * Set the virtual geometry in the disk label.
59 * If we like to make the geometry variable, we may change
60 * dkl_ncyl and dkl_pcyl later.
65 i_to_4_byte(cd_label
.dkl_vtoc
.v_version
, V_VERSION
);
66 i_to_2_byte(cd_label
.dkl_vtoc
.v_nparts
, NDKMAP
);
67 i_to_4_byte(cd_label
.dkl_vtoc
.v_sanity
, VTOC_SANE
);
69 i_to_2_byte(cd_label
.dkl_rpm
, CD_RPM
);
70 i_to_2_byte(cd_label
.dkl_pcyl
, CD_PCYL
);
71 i_to_2_byte(cd_label
.dkl_apc
, CD_APC
);
72 i_to_2_byte(cd_label
.dkl_intrlv
, CD_INTRLV
);
73 i_to_2_byte(cd_label
.dkl_ncyl
, CD_NCYL
);
74 i_to_2_byte(cd_label
.dkl_acyl
, CD_ACYL
);
75 i_to_2_byte(cd_label
.dkl_nhead
, CD_NHEAD
);
76 i_to_2_byte(cd_label
.dkl_nsect
, CD_NSECT
);
78 cd_label
.dkl_magic
[0] = DKL_MAGIC_0
;
79 cd_label
.dkl_magic
[1] = DKL_MAGIC_1
;
85 li_to_4_byte(sx86_label
.dkl_vtoc
.v_sanity
, VTOC_SANE
);
86 li_to_4_byte(sx86_label
.dkl_vtoc
.v_version
, V_VERSION
);
87 li_to_2_byte(sx86_label
.dkl_vtoc
.v_sectorsz
, 512);
88 li_to_2_byte(sx86_label
.dkl_vtoc
.v_nparts
, NX86MAP
);
90 li_to_4_byte(sx86_label
.dkl_pcyl
, CD_PCYL
);
91 li_to_4_byte(sx86_label
.dkl_ncyl
, CD_NCYL
);
92 li_to_2_byte(sx86_label
.dkl_acyl
, CD_ACYL
);
93 li_to_2_byte(sx86_label
.dkl_bcyl
, 0);
95 li_to_4_byte(sx86_label
.dkl_nhead
, CD_NHEAD
);
96 li_to_4_byte(sx86_label
.dkl_nsect
, CD_NSECT
);
97 li_to_2_byte(sx86_label
.dkl_intrlv
, CD_INTRLV
);
98 li_to_2_byte(sx86_label
.dkl_skew
, 0);
99 li_to_2_byte(sx86_label
.dkl_apc
, CD_APC
);
100 li_to_2_byte(sx86_label
.dkl_rpm
, CD_RPM
);
102 li_to_2_byte(sx86_label
.dkl_write_reinstruct
, 0);
103 li_to_2_byte(sx86_label
.dkl_read_reinstruct
, 0);
105 li_to_2_byte(sx86_label
.dkl_magic
, DKL_MAGIC
);
109 * For command line parser: set ASCII label.
112 sparc_boot_label(label
)
115 strncpy(cd_label
.dkl_ascilabel
, label
, 127);
116 cd_label
.dkl_ascilabel
[127] = '\0';
121 sunx86_boot_label(label
)
124 strncpy(sx86_label
.dkl_vtoc
.v_asciilabel
, label
, 127);
125 sx86_label
.dkl_vtoc
.v_asciilabel
[127] = '\0';
130 * Parse the command line argument for boot images.
133 scan_sparc_boot(files
)
140 extern int use_sparcboot
;
141 extern int use_sunx86boot
;
145 _("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
152 comerrno(EX_BAD
, _("Too many boot partitions.\n"));
153 boot_files
[i
++] = files
;
154 if ((p
= strchr(files
, ',')) != NULL
)
159 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[0].p_tag
, V_USR
);
160 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[0].p_flag
, V_RONLY
);
161 for (i
= 0; i
< NDKMAP
; i
++) {
163 if (p
== NULL
|| *p
== '\0')
165 if (strcmp(p
, "...") == '\0')
168 status
= stat_filter(p
, &statbuf
);
169 if (status
< 0 || access(p
, R_OK
) < 0)
170 comerr(_("Cannot access '%s'.\n"), p
);
172 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
,
173 roundup(statbuf
.st_size
, CD_CYLSIZE
)/512);
175 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_tag
, V_ROOT
);
176 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_flag
, V_RONLY
);
182 scan_sunx86_boot(files
)
189 extern int use_sparcboot
;
190 extern int use_sunx86boot
;
194 _("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
202 comerrno(EX_BAD
, _("Too many boot partitions.\n"));
203 boot_files
[i
++] = files
;
204 if ((p
= strchr(files
, ',')) != NULL
)
209 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[0].p_tag
, V_ROOT
); /* UFS */
210 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[0].p_flag
, V_RONLY
);
211 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_tag
, V_USR
); /* ISO */
212 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_flag
, V_RONLY
);
213 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_tag
, 0); /* ALL */
214 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_flag
, 0);
215 for (i
= 0; i
< NDKMAP
; i
++) {
217 if (p
== NULL
|| *p
== '\0')
219 if (i
== 1 || i
== 2) {
221 _("Partition %d may not have a filename.\n"), i
);
224 status
= stat_filter(p
, &statbuf
);
225 if (status
< 0 || access(p
, R_OK
) < 0)
226 comerr(_("Cannot access '%s'.\n"), p
);
228 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_size
,
229 roundup(statbuf
.st_size
, CD_CYLSIZE
)/512);
232 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_tag
, V_USR
);
233 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_flag
, V_RONLY
);
240 * Finish the Sun disk label and compute the size of the additional data.
253 * Compute the size of the padding for the iso9660 image
254 * to allow the next partition to start on a cylinder boundary.
256 last
= roundup(last_extent
, (CD_CYLSIZE
/SECTOR_SIZE
));
258 i_to_4_byte(cd_label
.dkl_map
[0].dkl_nblk
, last
*4);
260 for (i
= 0; i
< NDKMAP
; i
++) {
262 if (p
!= NULL
&& strcmp(p
, "...") == '\0') {
266 if ((nblk
= a_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
)) == 0)
269 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_cylno
, cyl
);
270 cyl
+= nblk
/ (CD_CYLSIZE
/512);
275 return (last
-last_extent
+bsize
);
279 * A typical Solaris boot/install CD from a Sun CD set looks
282 * UFS Part 0 tag 2 flag 10 start 3839 size 1314560
283 * ISO Part 1 tag 4 flag 10 start 0 size 3839
284 * ALL Part 2 tag 0 flag 0 start 0 size 1318400
294 int partoff
= 1; /* The offset of the Solaris 0x82 partition */
297 * Compute the size of the padding for the iso9660 image
298 * to allow the next partition to start on a cylinder boundary.
300 last
= roundup(last_extent
, (CD_CYLSIZE
/SECTOR_SIZE
));
302 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_size
, last
*4);
305 * Note that the Solaris fdisk partition with fdisk signature 0x82
306 * is created at fixed offset 1 sector == 512 Bytes by this
308 * We need subtract this partition offset from all absolute
309 * partition offsets in order to get offsets relative to the
310 * Solaris primary partition.
313 for (i
= 0; i
< NDKMAP
; i
++) {
314 if (i
== 2) /* Never include the whole disk in */
315 continue; /* size/offset computations */
317 if ((nblk
= la_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_size
)) == 0)
320 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_start
,
321 cyl
*(CD_CYLSIZE
/512)-partoff
);
322 cyl
+= nblk
/ (CD_CYLSIZE
/512);
326 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[0].p_start
, last
*4-partoff
);
327 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_start
, 0);
328 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_size
, last
*4-partoff
);
329 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_start
, 0);
330 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_size
, last
*4+bsize
);
332 fdisk_part
.part
[0].pr_status
= STATUS_ACTIVE
;
333 fdisk_part
.part
[0].pr_type
= TYPE_SOLARIS
;
334 li_to_4_byte(fdisk_part
.part
[0].pr_partoff
, partoff
);
335 li_to_4_byte(fdisk_part
.part
[0].pr_nsect
, last
*4+bsize
-partoff
);
336 fdisk_part
.magic
[0] = 0x55;
337 fdisk_part
.magic
[1] = 0xAA;
340 return (last
-last_extent
+bsize
);
344 * Duplicate a partition of the Sun disk label until all partitions are filled up.
355 if (part
< 1 || part
>= NDKMAP
)
357 cyl
= a_to_4_byte(cd_label
.dkl_map
[part
-1].dkl_cylno
);
358 nblk
= a_to_4_byte(cd_label
.dkl_map
[part
-1].dkl_nblk
);
360 for (i
= part
; i
< NDKMAP
; i
++) {
361 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_cylno
, cyl
);
362 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
, nblk
);
364 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_tag
, V_ROOT
);
365 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_flag
, V_RONLY
);
370 * Write out Sun boot partitions.
373 sunboot_write(outfile
)
376 char buffer
[SECTOR_SIZE
];
384 memset(buffer
, 0, sizeof (buffer
));
387 * Write padding to the iso9660 image to allow the
388 * boot partitions to start on a cylinder boundary.
390 amt
= roundup(last_extent_written
, (CD_CYLSIZE
/SECTOR_SIZE
)) - last_extent_written
;
391 for (n
= 0; n
< amt
; n
++) {
392 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
393 last_extent_written
++;
399 for (; i
< NDKMAP
; i
++) {
400 if (use_sunx86boot
&& (i
== 1 || i
== 2))
403 if (p
== NULL
|| *p
== '\0')
405 if (p
!= NULL
&& strcmp(p
, "...") == '\0')
407 if (use_sunx86boot
) {
408 if ((nblk
= la_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_size
)) == 0)
411 if ((nblk
= a_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
)) == 0)
414 if ((f
= open(boot_files
[i
], O_RDONLY
| O_BINARY
)) < 0)
415 comerr(_("Cannot open '%s'.\n"), boot_files
[i
]);
418 for (n
= 0; n
< amt
; n
++) {
419 memset(buffer
, 0, sizeof (buffer
));
420 if (read(f
, buffer
, SECTOR_SIZE
) < 0)
421 comerr(_("Read error on '%s'.\n"), boot_files
[i
]);
422 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
423 last_extent_written
++;
427 fprintf(stderr
, _("Total extents including %s boot = %u\n"),
428 use_sunx86boot
? "Solaris x86":"sparc",
429 last_extent_written
- session_start
);
434 * Do size management for the Sun disk label that is located in the first
438 sunlabel_size(starting_extent
)
439 UInt32_t starting_extent
;
441 if (last_extent
!= session_start
)
442 comerrno(EX_BAD
, _("Cannot create sparc boot on offset != 0.\n"));
448 * Compute the checksum and write a Sun disk label to the first sector
450 * If the -generic-boot option has been specified too, overlay the
451 * Sun disk label on the first 512 bytes of the generic boot code.
454 sunlabel_write(outfile
)
457 char buffer
[SECTOR_SIZE
];
459 register short count
= (512/2) - 1;
462 memset(buffer
, 0, sizeof (buffer
));
464 if ((f
= open(genboot_image
, O_RDONLY
| O_BINARY
)) < 0)
465 comerr(_("Cannot open '%s'.\n"), genboot_image
);
467 if (read(f
, buffer
, SECTOR_SIZE
) < 0)
468 comerr(_("Read error on '%s'.\n"), genboot_image
);
472 if (use_sunx86boot
) {
473 if (sx86_label
.dkl_vtoc
.v_asciilabel
[0] == '\0')
474 strcpy(sx86_label
.dkl_vtoc
.v_asciilabel
, CD_X86LABEL
);
476 p
= (char *)&sx86_label
;
477 sx86_label
.dkl_cksum
[0] = 0;
478 sx86_label
.dkl_cksum
[1] = 0;
479 while (count
-- > 0) {
480 sx86_label
.dkl_cksum
[0] ^= *p
++;
481 sx86_label
.dkl_cksum
[1] ^= *p
++;
483 memcpy(&buffer
[0x1BE], fdisk_part
.part
, sizeof (fdisk_part
.part
));
487 memcpy(&buffer
[1024], &sx86_label
, 512);
490 * If we don't already have a Sun disk label text
491 * set up the default.
493 if (cd_label
.dkl_ascilabel
[0] == '\0')
494 strcpy(cd_label
.dkl_ascilabel
, CD_DEFLABEL
);
496 p
= (char *)&cd_label
;
497 cd_label
.dkl_cksum
[0] = 0;
498 cd_label
.dkl_cksum
[1] = 0;
500 cd_label
.dkl_cksum
[0] ^= *p
++;
501 cd_label
.dkl_cksum
[1] ^= *p
++;
503 memcpy(buffer
, &cd_label
, 512);
506 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
507 last_extent_written
++;
512 * Do size management for the generic boot code on sectors 0..16.
515 genboot_size(starting_extent
)
516 UInt32_t starting_extent
;
518 if (last_extent
> (session_start
+ 1))
519 comerrno(EX_BAD
, _("Cannot create generic boot on offset != 0.\n"));
520 last_extent
= session_start
+ 16;
525 * Write the generic boot code to sectors 0..16.
526 * If there is a Sun disk label, start writing at sector 1.
529 genboot_write(outfile
)
532 char buffer
[SECTOR_SIZE
];
536 if ((f
= open(genboot_image
, O_RDONLY
| O_BINARY
)) < 0)
537 comerr(_("Cannot open '%s'.\n"), genboot_image
);
539 for (i
= 0; i
< 16; i
++) {
540 memset(buffer
, 0, sizeof (buffer
));
541 if (read(f
, buffer
, SECTOR_SIZE
) < 0)
542 comerr(_("Read error on '%s'.\n"), genboot_image
);
544 if (i
!= 0 || last_extent_written
== session_start
) {
545 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
546 last_extent_written
++;
553 struct output_fragment sunboot_desc
= {NULL
, NULL
, NULL
, sunboot_write
, "Sun Boot" };
554 struct output_fragment sunlabel_desc
= {NULL
, sunlabel_size
, NULL
, sunlabel_write
, "Sun Disk Label" };
555 struct output_fragment genboot_desc
= {NULL
, genboot_size
, NULL
, genboot_write
, "Generic Boot" };