Module Name: src Committed By: tsutsui Date: Sun May 19 15:48:58 UTC 2024
Modified Files: src/usr.sbin/installboot: Makefile fstypes.c installboot.8 installboot.h src/usr.sbin/installboot/arch: hp300.c Added Files: src/usr.sbin/installboot: cd9660.c Log Message: Add cd9660 support to search a bootloader file in the target file system. Also add CD boot support for hp300, using a bootloader file in cd9660 fs. This is a tool's part to close PR/54455. HP 9000/300 machines read LIF directory entry allocated after the LIF volume header at the top of the boot disk during bootstrap, and a bootstrap file must be contiguously allocated on the disk due to limitation of the LIF specification. Current NetBSD/hp300's bootloader is larger than ~80KB so we have to prepare a special 'boot' partition for FFS (that has only 8KB (ffsv1) or 32KB (ffsv2) spaces) disks to put such a large bootloader. On the other hand, on ISO9660 fs all files are allocated contiguously so we can specify a bootloader file in the target ISO9660 directly in the LIF directory entry. Note we can simply use the existing "append" option to create bootable CD ISO for hp300, but it looks some emulators (at leaset MAME) reject such non-standard ISO files, i.e. with an appended bootloader file at the end of the image. To generate a diff of this commit: cvs rdiff -u -r1.58 -r1.59 src/usr.sbin/installboot/Makefile cvs rdiff -u -r0 -r1.1 src/usr.sbin/installboot/cd9660.c cvs rdiff -u -r1.13 -r1.14 src/usr.sbin/installboot/fstypes.c cvs rdiff -u -r1.108 -r1.109 src/usr.sbin/installboot/installboot.8 cvs rdiff -u -r1.44 -r1.45 src/usr.sbin/installboot/installboot.h cvs rdiff -u -r1.18 -r1.19 src/usr.sbin/installboot/arch/hp300.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/installboot/Makefile diff -u src/usr.sbin/installboot/Makefile:1.58 src/usr.sbin/installboot/Makefile:1.59 --- src/usr.sbin/installboot/Makefile:1.58 Sat Jun 3 21:26:29 2023 +++ src/usr.sbin/installboot/Makefile Sun May 19 15:48:57 2024 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.58 2023/06/03 21:26:29 lukem Exp $ +# $NetBSD: Makefile,v 1.59 2024/05/19 15:48:57 tsutsui Exp $ # .include <bsd.own.mk> @@ -69,9 +69,31 @@ SRCS+= ffs_bswap.c #SRCS+= ext2fs.c ext2fs_bswap.c .endif +.if !empty(ARCH_FILES:C/(hp300|macppc)/cd9660/:Mcd9660.c) && \ + !defined(SMALLPROG) +CPPFLAGS+= -DSUPPORT_CD9660 +SRCS+= cd9660.c cd9660_util.c + +.if !make(obj) && !make(clean) && !make(cleandir) +.BEGIN: + -rm -rf fs + ${HOST_INSTALL_DIR} fs + ${HOST_INSTALL_DIR} fs/cd9660 + ${HOST_LN} -s ${NETBSDSRCDIR}/sys/fs/unicode.h fs + ${HOST_LN} -s ${NETBSDSRCDIR}/sys/fs/cd9660/iso.h fs/cd9660 + ${HOST_LN} -s ${NETBSDSRCDIR}/sys/fs/cd9660/cd9660_extern.h fs/cd9660 +.endif + +cleandir distclean: cleaninc + +cleaninc: + -rm -rf fs +.endif + UFSSRC= ${NETBSDSRCDIR}/sys/ufs +CD9660SRC= ${NETBSDSRCDIR}/sys/fs/cd9660 CPPFLAGS+= -I${.CURDIR} -I. -.PATH: ${.CURDIR}/arch ${UFSSRC}/ffs ${UFSSRC}/ext2fs +.PATH: ${.CURDIR}/arch ${UFSSRC}/ffs ${UFSSRC}/ext2fs ${CD9660SRC} .if !defined(HOSTPROGNAME) .for f in i386 macppc Index: src/usr.sbin/installboot/fstypes.c diff -u src/usr.sbin/installboot/fstypes.c:1.13 src/usr.sbin/installboot/fstypes.c:1.14 --- src/usr.sbin/installboot/fstypes.c:1.13 Thu Jan 14 16:27:49 2010 +++ src/usr.sbin/installboot/fstypes.c Sun May 19 15:48:57 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: fstypes.c,v 1.13 2010/01/14 16:27:49 tsutsui Exp $ */ +/* $NetBSD: fstypes.c,v 1.14 2024/05/19 15:48:57 tsutsui Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #include <sys/cdefs.h> #if !defined(__lint) -__RCSID("$NetBSD: fstypes.c,v 1.13 2010/01/14 16:27:49 tsutsui Exp $"); +__RCSID("$NetBSD: fstypes.c,v 1.14 2024/05/19 15:48:57 tsutsui Exp $"); #endif /* !__lint */ #include <sys/types.h> @@ -48,11 +48,33 @@ __RCSID("$NetBSD: fstypes.c,v 1.13 2010/ struct ib_fs fstypes[] = { #ifndef NO_STAGE2 - { .name = "ffs", .match = ffs_match, .findstage2 = ffs_findstage2 }, - { .name = "raid", .match = raid_match, .findstage2 = ffs_findstage2 }, - { .name = "raw", .match = raw_match, .findstage2 = raw_findstage2 }, + { + .name = "ffs", + .match = ffs_match, + .findstage2 = ffs_findstage2 + }, + { + .name = "raid", + .match = raid_match, + .findstage2 = ffs_findstage2 + }, +#ifdef SUPPORT_CD9660 + { + .name = "cd9660", + .match = cd9660_match, + .findstage2 = cd9660_findstage2 + }, #endif - { .name = NULL, } + /* raw_match() always matches, so raw should be at the end. */ + { + .name = "raw", + .match = raw_match, + .findstage2 = raw_findstage2 + }, +#endif + { + .name = NULL + } }; #ifndef NO_STAGE2 Index: src/usr.sbin/installboot/installboot.8 diff -u src/usr.sbin/installboot/installboot.8:1.108 src/usr.sbin/installboot/installboot.8:1.109 --- src/usr.sbin/installboot/installboot.8:1.108 Tue Dec 26 06:00:35 2023 +++ src/usr.sbin/installboot/installboot.8 Sun May 19 15:48:57 2024 @@ -1,4 +1,4 @@ -.\" $NetBSD: installboot.8,v 1.108 2023/12/26 06:00:35 mrg Exp $ +.\" $NetBSD: installboot.8,v 1.109 2024/05/19 15:48:57 tsutsui Exp $ .\" .\" Copyright (c) 2002-2023 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -32,7 +32,7 @@ .\" Usage: \*(UB .ds UB U\(hyBoot . -.Dd December 25, 2023 +.Dd May 19, 2024 .Dt INSTALLBOOT 8 .Os .Sh NAME @@ -479,6 +479,9 @@ Fast File System. .It Ic raid Mirrored RAIDframe File System. . +.It Ic cd9660 +ISO 9660 File System. +. .It Ic raw .Dq Raw image. Index: src/usr.sbin/installboot/installboot.h diff -u src/usr.sbin/installboot/installboot.h:1.44 src/usr.sbin/installboot/installboot.h:1.45 --- src/usr.sbin/installboot/installboot.h:1.44 Sun May 19 15:44:21 2024 +++ src/usr.sbin/installboot/installboot.h Sun May 19 15:48:57 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: installboot.h,v 1.44 2024/05/19 15:44:21 tsutsui Exp $ */ +/* $NetBSD: installboot.h,v 1.45 2024/05/19 15:48:57 tsutsui Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -171,6 +171,10 @@ int shared_bbinfo_clearboot(ib_params * int shared_bbinfo_setboot(ib_params *, struct bbinfo_params *, int (*)(ib_params *, struct bbinfo_params *, uint8_t *)); + /* cd9660.c */ +int cd9660_match(ib_params *); +int cd9660_findstage2(ib_params *, uint32_t *, ib_block *); + /* ext2fs.c */ int ext2fs_match(ib_params *); int ext2fs_findstage2(ib_params *, uint32_t *, ib_block *); Index: src/usr.sbin/installboot/arch/hp300.c diff -u src/usr.sbin/installboot/arch/hp300.c:1.18 src/usr.sbin/installboot/arch/hp300.c:1.19 --- src/usr.sbin/installboot/arch/hp300.c:1.18 Sat May 11 22:10:27 2024 +++ src/usr.sbin/installboot/arch/hp300.c Sun May 19 15:48:57 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: hp300.c,v 1.18 2024/05/11 22:10:27 tsutsui Exp $ */ +/* $NetBSD: hp300.c,v 1.19 2024/05/19 15:48:57 tsutsui Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #include <sys/cdefs.h> #if !defined(__lint) -__RCSID("$NetBSD: hp300.c,v 1.18 2024/05/11 22:10:27 tsutsui Exp $"); +__RCSID("$NetBSD: hp300.c,v 1.19 2024/05/19 15:48:57 tsutsui Exp $"); #endif /* !__lint */ /* We need the target disklabel.h, not the hosts one..... */ @@ -62,6 +62,9 @@ __RCSID("$NetBSD: hp300.c,v 1.18 2024/05 #include "installboot.h" +#define HP300_MAXBLOCKS 1 /* Only contiguous blocks are expected. */ +#define LIF_VOLDIRSIZE 1024 /* size of LIF volume header and directory */ + static int hp300_setboot(ib_params *); struct ib_mach ib_mach_hp300 = { @@ -77,6 +80,7 @@ hp300_setboot(ib_params *params) { int retval; uint8_t *bootstrap; + size_t bootstrap_size; ssize_t rv; struct partition *boot; struct hp300_lifdir *lifdir; @@ -84,6 +88,10 @@ hp300_setboot(ib_params *params) int i; unsigned int secsize = HP300_SECTSIZE; uint64_t boot_size, boot_offset; +#ifdef SUPPORT_CD9660 + uint32_t nblk; + ib_block *blocks; +#endif struct disklabel *label; assert(params != NULL); @@ -101,6 +109,64 @@ hp300_setboot(ib_params *params) goto done; } +#ifdef SUPPORT_CD9660 + if (params->stage2 != NULL) { + /* + * Use contiguous blocks of SYS_BOOT in the target filesystem + * (assuming ISO9660) for a LIF directory entry used + * by BOOTROM on bootstrap. + */ + if (strcmp(params->fstype->name, "cd9660") != 0) { + warn("Target filesystem `%s' is unexpected", + params->fstype->name); + } + + if (S_ISREG(params->fsstat.st_mode)) { + if (fsync(params->fsfd) == -1) + warn("Synchronising file system `%s'", + params->filesystem); + } else { + /* Don't allow real file systems for sanity */ + warnx("`%s' must be a regular file to append " + "a bootstrap", params->filesystem); + goto done; + } + + /* Allocate space for our block list. */ + nblk = HP300_MAXBLOCKS; + blocks = malloc(sizeof(*blocks) * nblk); + if (blocks == NULL) { + warn("Allocating %lu bytes for block list", + (unsigned long)sizeof(*blocks) * nblk); + goto done; + } + + /* Check the block of for the SYS_UBOOT in the target fs */ + if (!params->fstype->findstage2(params, &nblk, blocks)) + goto done; + + if (nblk == 0) { + warnx("Secondary bootstrap `%s' is empty", + params->stage2); + goto done; + } else if (nblk > 1) { + warnx("Secondary bootstrap `%s' doesn't have " + "contiguous blocks", params->stage2); + goto done; + } + + boot_offset = blocks[0].block * params->fstype->blocksize; + /* need to read only LIF volume and directories */ + bootstrap_size = LIF_VOLDIRSIZE; + + if ((params->flags & IB_VERBOSE) != 0) { + printf("Bootstrap `%s' found at offset %lu in `%s'\n", + params->stage2, (unsigned long)boot_offset, + params->filesystem); + } + + } else +#endif if (params->flags & IB_APPEND) { if (!S_ISREG(params->fsstat.st_mode)) { warnx( @@ -157,11 +223,27 @@ hp300_setboot(ib_params *params) } } - bootstrap = mmap(NULL, params->s1stat.st_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE, params->s1fd, 0); - if (bootstrap == MAP_FAILED) { - warn("mmapping `%s'", params->stage1); - goto done; +#ifdef SUPPORT_CD9660 + if (params->stage2 != NULL) { + /* Use bootstrap file in the target filesystem. */ + bootstrap = mmap(NULL, bootstrap_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, params->fsfd, + boot_offset); + if (bootstrap == MAP_FAILED) { + warn("mmapping `%s'", params->filesystem); + goto done; + } + } else +#endif + { + /* Use bootstrap specified as stage1. */ + bootstrap_size = params->s1stat.st_size; + bootstrap = mmap(NULL, bootstrap_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, params->s1fd, 0); + if (bootstrap == MAP_FAILED) { + warn("mmapping `%s'", params->stage1); + goto done; + } } /* Relocate files, sanity check LIF directory on the way */ @@ -187,8 +269,8 @@ hp300_setboot(ib_params *params) } /* Write LIF volume header and directory to sectors 0 and 1 */ - rv = pwrite(params->fsfd, bootstrap, 1024, 0); - if (rv != 1024) { + rv = pwrite(params->fsfd, bootstrap, LIF_VOLDIRSIZE, 0); + if (rv != LIF_VOLDIRSIZE) { if (rv == -1) warn("Writing `%s'", params->filesystem); else @@ -196,6 +278,17 @@ hp300_setboot(ib_params *params) goto done; } +#ifdef SUPPORT_CD9660 + if (params->stage2 != NULL) { + /* + * Bootstrap in the target filesystem is used. + * No need to write bootstrap to BOOT partition. + */ + retval = 1; + goto done; + } +#endif + /* Write files to BOOT partition */ offset = boot_offset <= HP300_SECTSIZE * 16 ? HP300_SECTSIZE * 16 : 0; i = roundup(params->s1stat.st_size, secsize) - offset; @@ -216,6 +309,6 @@ hp300_setboot(ib_params *params) if (label != NULL) free(label); if (bootstrap != MAP_FAILED) - munmap(bootstrap, params->s1stat.st_size); + munmap(bootstrap, bootstrap_size); return retval; } Added files: Index: src/usr.sbin/installboot/cd9660.c diff -u /dev/null src/usr.sbin/installboot/cd9660.c:1.1 --- /dev/null Sun May 19 15:48:58 2024 +++ src/usr.sbin/installboot/cd9660.c Sun May 19 15:48:57 2024 @@ -0,0 +1,234 @@ +/* $NetBSD: cd9660.c,v 1.1 2024/05/19 15:48:57 tsutsui Exp $ */ + +/*- + * Copyright (c) 2005 Izumi Tsutsui. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +#if defined(__RCSID) && !defined(__lint) +__RCSID("$NetBSD: cd9660.c,v 1.1 2024/05/19 15:48:57 tsutsui Exp $"); +#endif /* !__lint */ + +#include <sys/param.h> + +#if !HAVE_NBTOOL_CONFIG_H +#include <sys/mount.h> +#endif + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <dirent.h> + +#include <fs/cd9660/iso.h> +#include <fs/cd9660/cd9660_extern.h> + +#include "installboot.h" + +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#define MAXLEN 16 + + +int +cd9660_match(ib_params *params) +{ + int rv, blocksize; + struct iso_primary_descriptor ipd; + + assert(params != NULL); + assert(params->fstype != NULL); + assert(params->fsfd != -1); + + rv = pread(params->fsfd, &ipd, sizeof(ipd), + ISO_DEFAULT_BLOCK_SIZE * 16); + if (rv == -1) { + warn("Reading primary descriptor in `%s'", params->filesystem); + return 0; + } else if (rv != sizeof(ipd)) { + warnx("Reading primary descriptor in `%s': short read", + params->filesystem); + return 0; + } + + if (ipd.type[0] != ISO_VD_PRIMARY || + strncmp(ipd.id, ISO_STANDARD_ID, sizeof(ipd.id)) != 0 || + ipd.version[0] != 1) { + warnx("Filesystem `%s' is not ISO9660 format", + params->filesystem); + return 0; + } + + blocksize = isonum_723((u_char *)ipd.logical_block_size); + if (blocksize != ISO_DEFAULT_BLOCK_SIZE) { + warnx("Invalid blocksize %d in `%s'", + blocksize, params->filesystem); + return 0; + } + + params->fstype->blocksize = blocksize; + params->fstype->needswap = 0; + + return 1; +} + +int +cd9660_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks) +{ + uint8_t buf[ISO_DEFAULT_BLOCK_SIZE]; + char name[ISO_MAXNAMLEN]; + char *stage2; + off_t loc; + int rv, blocksize, found; + u_int i; + struct iso_primary_descriptor ipd; + struct iso_directory_record *idr; + + assert(params != NULL); + assert(params->stage2 != NULL); + assert(maxblk != NULL); + assert(blocks != NULL); + +#if 0 + if (params->flags & IB_STAGE2START) + return hardcode_stage2(params, maxblk, blocks); +#endif + + /* The secondary bootstrap must be clearly in /. */ + strlcpy(name, params->stage2, ISO_MAXNAMLEN); + stage2 = name; + if (stage2[0] == '/') + stage2++; + if (strchr(stage2, '/') != NULL) { + warnx("The secondary bootstrap `%s' must be in / " + "on filesystem `%s'", params->stage2, params->filesystem); + return 0; + } + if (strchr(stage2, '.') == NULL) { + /* + * XXX should fix isofncmp()? + */ + strlcat(name, ".", ISO_MAXNAMLEN); + } + + rv = pread(params->fsfd, &ipd, sizeof(ipd), + ISO_DEFAULT_BLOCK_SIZE * 16); + if (rv == -1) { + warn("Reading primary descriptor in `%s'", params->filesystem); + return 0; + } else if (rv != sizeof(ipd)) { + warnx("Reading primary descriptor in `%s': short read", + params->filesystem); + return 0; + } + blocksize = isonum_723((u_char *)ipd.logical_block_size); + + idr = (void *)ipd.root_directory_record; + loc = (off_t)isonum_733(idr->extent) * blocksize; + rv = pread(params->fsfd, buf, blocksize, loc); + if (rv == -1) { + warn("Reading root directory record in `%s'", + params->filesystem); + return 0; + } else if (rv != sizeof(ipd)) { + warnx("Reading root directory record in `%s': short read", + params->filesystem); + return 0; + } + + found = 0; + for (i = 0; i < blocksize - sizeof(struct iso_directory_record); + i += (u_char)idr->length[0]) { + idr = (void *)&buf[i]; + +#ifdef DEBUG + printf("i = %d, idr->length[0] = %3d\n", + i, (u_char)idr->length[0]); +#endif + /* check end of entries */ + if (idr->length[0] == 0) { +#ifdef DEBUG + printf("end of entries\n"); +#endif + break; + } + + if (idr->flags[0] & 2) { + /* skip directory entries */ +#ifdef DEBUG + printf("skip directory entry\n"); +#endif + continue; + } + if (idr->name_len[0] == 1 && + (idr->name[0] == 0 || idr->name[0] == 1)) { + /* skip "." and ".." */ +#ifdef DEBUG + printf("skip dot dot\n"); +#endif + continue; + } +#ifdef DEBUG + { + int j; + + printf("filename:"); + for (j = 0; j < isonum_711(idr->name_len); j++) + printf("%c", idr->name[j]); + printf("\n"); + } +#endif + if (isofncmp((u_char *)stage2, strlen(stage2), + (u_char *)idr->name, + isonum_711((u_char *)idr->name_len), 0) == 0) { + found = 1; + /* ISO filesystem always has contiguous file blocks */ + blocks[0].block = (int64_t)isonum_733(idr->extent); + blocks[0].blocksize = + roundup(isonum_733(idr->size), blocksize); + *maxblk = 1; +#ifdef DEBUG + printf("block = %ld, blocksize = %ld\n", + (long)blocks[0].block, blocks[0].blocksize); +#endif + break; + } + } + + if (found == 0) { + warnx("Can't find secondary bootstrap `%s' in filesystem `%s'", + params->stage2, params->filesystem); + return 0; + } + + return 1; +}