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
16 #include <schily/fcntl.h>
17 #include <schily/utypes.h>
18 #include <schily/intcvt.h>
19 #include <schily/schily.h>
22 extern int use_sunx86boot
;
24 LOCAL
struct sun_label cd_label
;
25 LOCAL
struct x86_label sx86_label
;
26 LOCAL
struct pc_part fdisk_part
;
27 LOCAL
char *boot_files
[NDKMAP
]; /* Change this for > 8 x86 parts */
29 LOCAL
void init_sparc_label
__PR((void));
30 LOCAL
void init_sunx86_label
__PR((void));
31 EXPORT
int sparc_boot_label
__PR((char *label
));
32 EXPORT
int sunx86_boot_label
__PR((char *label
));
33 EXPORT
int scan_sparc_boot
__PR((char *files
));
34 EXPORT
int scan_sunx86_boot
__PR((char *files
));
35 EXPORT
int make_sun_label
__PR((void));
36 EXPORT
int make_sunx86_label
__PR((void));
37 LOCAL
void dup_sun_label
__PR((int part
));
38 LOCAL
int sunboot_write
__PR((FILE *outfile
));
39 LOCAL
int sunlabel_size
__PR((UInt32_t starting_extent
));
40 LOCAL
int sunlabel_write
__PR((FILE *outfile
));
41 LOCAL
int genboot_size
__PR((UInt32_t starting_extent
));
42 LOCAL
int genboot_write
__PR((FILE *outfile
));
45 * Set the virtual geometry in the disk label.
46 * If we like to make the geometry variable, we may change
47 * dkl_ncyl and dkl_pcyl later.
52 i_to_4_byte(cd_label
.dkl_vtoc
.v_version
, V_VERSION
);
53 i_to_2_byte(cd_label
.dkl_vtoc
.v_nparts
, NDKMAP
);
54 i_to_4_byte(cd_label
.dkl_vtoc
.v_sanity
, VTOC_SANE
);
56 i_to_2_byte(cd_label
.dkl_rpm
, CD_RPM
);
57 i_to_2_byte(cd_label
.dkl_pcyl
, CD_PCYL
);
58 i_to_2_byte(cd_label
.dkl_apc
, CD_APC
);
59 i_to_2_byte(cd_label
.dkl_intrlv
, CD_INTRLV
);
60 i_to_2_byte(cd_label
.dkl_ncyl
, CD_NCYL
);
61 i_to_2_byte(cd_label
.dkl_acyl
, CD_ACYL
);
62 i_to_2_byte(cd_label
.dkl_nhead
, CD_NHEAD
);
63 i_to_2_byte(cd_label
.dkl_nsect
, CD_NSECT
);
65 cd_label
.dkl_magic
[0] = DKL_MAGIC_0
;
66 cd_label
.dkl_magic
[1] = DKL_MAGIC_1
;
72 li_to_4_byte(sx86_label
.dkl_vtoc
.v_sanity
, VTOC_SANE
);
73 li_to_4_byte(sx86_label
.dkl_vtoc
.v_version
, V_VERSION
);
74 li_to_2_byte(sx86_label
.dkl_vtoc
.v_sectorsz
, 512);
75 li_to_2_byte(sx86_label
.dkl_vtoc
.v_nparts
, NX86MAP
);
77 li_to_4_byte(sx86_label
.dkl_pcyl
, CD_PCYL
);
78 li_to_4_byte(sx86_label
.dkl_ncyl
, CD_NCYL
);
79 li_to_2_byte(sx86_label
.dkl_acyl
, CD_ACYL
);
80 li_to_2_byte(sx86_label
.dkl_bcyl
, 0);
82 li_to_4_byte(sx86_label
.dkl_nhead
, CD_NHEAD
);
83 li_to_4_byte(sx86_label
.dkl_nsect
, CD_NSECT
);
84 li_to_2_byte(sx86_label
.dkl_intrlv
, CD_INTRLV
);
85 li_to_2_byte(sx86_label
.dkl_skew
, 0);
86 li_to_2_byte(sx86_label
.dkl_apc
, CD_APC
);
87 li_to_2_byte(sx86_label
.dkl_rpm
, CD_RPM
);
89 li_to_2_byte(sx86_label
.dkl_write_reinstruct
, 0);
90 li_to_2_byte(sx86_label
.dkl_read_reinstruct
, 0);
92 li_to_2_byte(sx86_label
.dkl_magic
, DKL_MAGIC
);
96 * For command line parser: set ASCII label.
99 sparc_boot_label(label
)
102 strncpy(cd_label
.dkl_ascilabel
, label
, 127);
103 cd_label
.dkl_ascilabel
[127] = '\0';
108 sunx86_boot_label(label
)
111 strncpy(sx86_label
.dkl_vtoc
.v_asciilabel
, label
, 127);
112 sx86_label
.dkl_vtoc
.v_asciilabel
[127] = '\0';
117 * Parse the command line argument for boot images.
120 scan_sparc_boot(files
)
127 extern int use_sparcboot
;
128 extern int use_sunx86boot
;
132 _("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
139 comerrno(EX_BAD
, _("Too many boot partitions.\n"));
140 boot_files
[i
++] = files
;
141 if ((p
= strchr(files
, ',')) != NULL
)
146 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[0].p_tag
, V_USR
);
147 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[0].p_flag
, V_RONLY
);
148 for (i
= 0; i
< NDKMAP
; i
++) {
150 if (p
== NULL
|| *p
== '\0')
152 if (strcmp(p
, "...") == '\0')
155 status
= stat_filter(p
, &statbuf
);
156 if (status
< 0 || access(p
, R_OK
) < 0)
157 comerr(_("Cannot access '%s'.\n"), p
);
159 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
,
160 roundup(statbuf
.st_size
, CD_CYLSIZE
)/512);
162 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_tag
, V_ROOT
);
163 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_flag
, V_RONLY
);
169 scan_sunx86_boot(files
)
176 extern int use_sparcboot
;
177 extern int use_sunx86boot
;
181 _("-sparc-boot and -sunx86-boot are mutual exclusive.\n"));
189 comerrno(EX_BAD
, _("Too many boot partitions.\n"));
190 boot_files
[i
++] = files
;
191 if ((p
= strchr(files
, ',')) != NULL
)
196 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[0].p_tag
, V_ROOT
); /* UFS */
197 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[0].p_flag
, V_RONLY
);
198 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_tag
, V_USR
); /* ISO */
199 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_flag
, V_RONLY
);
200 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_tag
, 0); /* ALL */
201 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_flag
, 0);
202 for (i
= 0; i
< NDKMAP
; i
++) {
204 if (p
== NULL
|| *p
== '\0')
206 if (i
== 1 || i
== 2) {
208 _("Partition %d may not have a filename.\n"), i
);
211 status
= stat_filter(p
, &statbuf
);
212 if (status
< 0 || access(p
, R_OK
) < 0)
213 comerr(_("Cannot access '%s'.\n"), p
);
215 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_size
,
216 roundup(statbuf
.st_size
, CD_CYLSIZE
)/512);
219 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_tag
, V_USR
);
220 li_to_2_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_flag
, V_RONLY
);
227 * Finish the Sun disk label and compute the size of the additional data.
240 * Compute the size of the padding for the iso9660 image
241 * to allow the next partition to start on a cylinder boundary.
243 last
= roundup(last_extent
, (CD_CYLSIZE
/SECTOR_SIZE
));
245 i_to_4_byte(cd_label
.dkl_map
[0].dkl_nblk
, last
*4);
247 for (i
= 0; i
< NDKMAP
; i
++) {
249 if (p
!= NULL
&& strcmp(p
, "...") == '\0') {
253 if ((nblk
= a_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
)) == 0)
256 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_cylno
, cyl
);
257 cyl
+= nblk
/ (CD_CYLSIZE
/512);
262 return (last
-last_extent
+bsize
);
266 * A typical Solaris boot/install CD from a Sun CD set looks
269 * UFS Part 0 tag 2 flag 10 start 3839 size 1314560
270 * ISO Part 1 tag 4 flag 10 start 0 size 3839
271 * ALL Part 2 tag 0 flag 0 start 0 size 1318400
281 int partoff
= 1; /* The offset of the Solaris 0x82 partition */
284 * Compute the size of the padding for the iso9660 image
285 * to allow the next partition to start on a cylinder boundary.
287 last
= roundup(last_extent
, (CD_CYLSIZE
/SECTOR_SIZE
));
289 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_size
, last
*4);
292 * Note that the Solaris fdisk partition with fdisk signature 0x82
293 * is created at fixed offset 1 sector == 512 Bytes by this
295 * We need subtract this partition offset from all absolute
296 * partition offsets in order to get offsets relative to the
297 * Solaris primary partition.
300 for (i
= 0; i
< NDKMAP
; i
++) {
301 if (i
== 2) /* Never include the whole disk in */
302 continue; /* size/offset computations */
304 if ((nblk
= la_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_size
)) == 0)
307 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_start
,
308 cyl
*(CD_CYLSIZE
/512)-partoff
);
309 cyl
+= nblk
/ (CD_CYLSIZE
/512);
313 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[0].p_start
, last
*4-partoff
);
314 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_start
, 0);
315 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[1].p_size
, last
*4-partoff
);
316 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_start
, 0);
317 li_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[2].p_size
, last
*4+bsize
);
319 fdisk_part
.part
[0].pr_status
= STATUS_ACTIVE
;
320 fdisk_part
.part
[0].pr_type
= TYPE_SOLARIS
;
321 li_to_4_byte(fdisk_part
.part
[0].pr_partoff
, partoff
);
322 li_to_4_byte(fdisk_part
.part
[0].pr_nsect
, last
*4+bsize
-partoff
);
323 fdisk_part
.magic
[0] = 0x55;
324 fdisk_part
.magic
[1] = 0xAA;
327 return (last
-last_extent
+bsize
);
331 * Duplicate a partition of the Sun disk label until all partitions are filled up.
342 if (part
< 1 || part
>= NDKMAP
)
344 cyl
= a_to_4_byte(cd_label
.dkl_map
[part
-1].dkl_cylno
);
345 nblk
= a_to_4_byte(cd_label
.dkl_map
[part
-1].dkl_nblk
);
347 for (i
= part
; i
< NDKMAP
; i
++) {
348 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_cylno
, cyl
);
349 i_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
, nblk
);
351 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_tag
, V_ROOT
);
352 i_to_2_byte(cd_label
.dkl_vtoc
.v_part
[i
].p_flag
, V_RONLY
);
357 * Write out Sun boot partitions.
360 sunboot_write(outfile
)
363 char buffer
[SECTOR_SIZE
];
371 memset(buffer
, 0, sizeof (buffer
));
374 * Write padding to the iso9660 image to allow the
375 * boot partitions to start on a cylinder boundary.
377 amt
= roundup(last_extent_written
, (CD_CYLSIZE
/SECTOR_SIZE
)) - last_extent_written
;
378 for (n
= 0; n
< amt
; n
++) {
379 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
380 last_extent_written
++;
386 for (; i
< NDKMAP
; i
++) {
387 if (use_sunx86boot
&& (i
== 1 || i
== 2))
390 if (p
== NULL
|| *p
== '\0')
392 if (p
!= NULL
&& strcmp(p
, "...") == '\0')
394 if (use_sunx86boot
) {
395 if ((nblk
= la_to_4_byte(sx86_label
.dkl_vtoc
.v_part
[i
].p_size
)) == 0)
398 if ((nblk
= a_to_4_byte(cd_label
.dkl_map
[i
].dkl_nblk
)) == 0)
401 if ((f
= open(boot_files
[i
], O_RDONLY
| O_BINARY
)) < 0)
402 comerr(_("Cannot open '%s'.\n"), boot_files
[i
]);
405 for (n
= 0; n
< amt
; n
++) {
406 memset(buffer
, 0, sizeof (buffer
));
407 if (read(f
, buffer
, SECTOR_SIZE
) < 0)
408 comerr(_("Read error on '%s'.\n"), boot_files
[i
]);
409 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
410 last_extent_written
++;
414 fprintf(stderr
, _("Total extents including %s boot = %u\n"),
415 use_sunx86boot
? "Solaris x86":"sparc",
416 last_extent_written
- session_start
);
421 * Do size management for the Sun disk label that is located in the first
425 sunlabel_size(starting_extent
)
426 UInt32_t starting_extent
;
428 if (last_extent
!= session_start
)
429 comerrno(EX_BAD
, _("Cannot create sparc boot on offset != 0.\n"));
435 * Compute the checksum and write a Sun disk label to the first sector
437 * If the -generic-boot option has been specified too, overlay the
438 * Sun disk label on the first 512 bytes of the generic boot code.
441 sunlabel_write(outfile
)
444 char buffer
[SECTOR_SIZE
];
446 register short count
= (512/2) - 1;
449 memset(buffer
, 0, sizeof (buffer
));
451 if ((f
= open(genboot_image
, O_RDONLY
| O_BINARY
)) < 0)
452 comerr(_("Cannot open '%s'.\n"), genboot_image
);
454 if (read(f
, buffer
, SECTOR_SIZE
) < 0)
455 comerr(_("Read error on '%s'.\n"), genboot_image
);
459 if (use_sunx86boot
) {
460 if (sx86_label
.dkl_vtoc
.v_asciilabel
[0] == '\0')
461 strcpy(sx86_label
.dkl_vtoc
.v_asciilabel
, CD_X86LABEL
);
463 p
= (char *)&sx86_label
;
464 sx86_label
.dkl_cksum
[0] = 0;
465 sx86_label
.dkl_cksum
[1] = 0;
466 while (count
-- > 0) {
467 sx86_label
.dkl_cksum
[0] ^= *p
++;
468 sx86_label
.dkl_cksum
[1] ^= *p
++;
470 memcpy(&buffer
[0x1BE], fdisk_part
.part
, sizeof (fdisk_part
.part
));
474 memcpy(&buffer
[1024], &sx86_label
, 512);
477 * If we don't already have a Sun disk label text
478 * set up the default.
480 if (cd_label
.dkl_ascilabel
[0] == '\0')
481 strcpy(cd_label
.dkl_ascilabel
, CD_DEFLABEL
);
483 p
= (char *)&cd_label
;
484 cd_label
.dkl_cksum
[0] = 0;
485 cd_label
.dkl_cksum
[1] = 0;
487 cd_label
.dkl_cksum
[0] ^= *p
++;
488 cd_label
.dkl_cksum
[1] ^= *p
++;
490 memcpy(buffer
, &cd_label
, 512);
493 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
494 last_extent_written
++;
499 * Do size management for the generic boot code on sectors 0..16.
502 genboot_size(starting_extent
)
503 UInt32_t starting_extent
;
505 if (last_extent
> (session_start
+ 1))
506 comerrno(EX_BAD
, _("Cannot create generic boot on offset != 0.\n"));
507 last_extent
= session_start
+ 16;
512 * Write the generic boot code to sectors 0..16.
513 * If there is a Sun disk label, start writing at sector 1.
516 genboot_write(outfile
)
519 char buffer
[SECTOR_SIZE
];
523 if ((f
= open(genboot_image
, O_RDONLY
| O_BINARY
)) < 0)
524 comerr(_("Cannot open '%s'.\n"), genboot_image
);
526 for (i
= 0; i
< 16; i
++) {
527 memset(buffer
, 0, sizeof (buffer
));
528 if (read(f
, buffer
, SECTOR_SIZE
) < 0)
529 comerr(_("Read error on '%s'.\n"), genboot_image
);
531 if (i
!= 0 || last_extent_written
== session_start
) {
532 xfwrite(buffer
, SECTOR_SIZE
, 1, outfile
, 0, FALSE
);
533 last_extent_written
++;
540 struct output_fragment sunboot_desc
= {NULL
, NULL
, NULL
, sunboot_write
, "Sun Boot" };
541 struct output_fragment sunlabel_desc
= {NULL
, sunlabel_size
, NULL
, sunlabel_write
, "Sun Disk Label" };
542 struct output_fragment genboot_desc
= {NULL
, genboot_size
, NULL
, genboot_write
, "Generic Boot" };