1 /* $NetBSD: next68k.c,v 1.10 2023/02/14 20:27:17 andvar Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by David Laight and Christian Limpach. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #if HAVE_NBTOOL_CONFIG_H 33 #include "nbtool_config.h" 34 #endif 35 36 #include <sys/cdefs.h> 37 #if !defined(__lint) 38 __RCSID("$NetBSD: next68k.c,v 1.10 2023/02/14 20:27:17 andvar Exp $"); 39 #endif /* !__lint */ 40 41 #include <sys/param.h> 42 43 #include <assert.h> 44 #include <err.h> 45 #include <md5.h> 46 #include <stddef.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 52 #include "installboot.h" 53 54 static uint16_t nextstep_checksum(const void *, const void *); 55 static int next68k_setboot(ib_params *); 56 57 struct ib_mach ib_mach_next68k = { 58 .name = "next68k", 59 .setboot = next68k_setboot, 60 .clearboot = no_clearboot, 61 .editboot = no_editboot, 62 }; 63 64 static uint16_t 65 nextstep_checksum(const void *vbuf, const void *vlimit) 66 { 67 const uint16_t *buf = vbuf; 68 const uint16_t *limit = vlimit; 69 u_int sum = 0; 70 71 while (buf < limit) { 72 sum += be16toh(*buf++); 73 } 74 sum += (sum >> 16); 75 return (sum & 0xffff); 76 } 77 78 static int 79 next68k_setboot(ib_params *params) 80 { 81 int retval, labelupdated; 82 uint8_t *bootbuf; 83 size_t bootsize; 84 ssize_t rv; 85 uint32_t cd_secsize; 86 int sec_netonb_mult; 87 struct next68k_disklabel *next68klabel; 88 uint16_t *checksum; 89 uint32_t fp, b0, b1; 90 91 assert(params != NULL); 92 assert(params->fsfd != -1); 93 assert(params->filesystem != NULL); 94 assert(params->s1fd != -1); 95 assert(params->stage1 != NULL); 96 97 retval = 0; 98 labelupdated = 0; 99 bootbuf = NULL; 100 101 next68klabel = malloc(NEXT68K_LABEL_SIZE); 102 if (next68klabel == NULL) { 103 warn("Allocating %lu bytes", (unsigned long)NEXT68K_LABEL_SIZE); 104 goto done; 105 } 106 107 /* 108 * Read in the next68k disklabel 109 */ 110 rv = pread(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE, 111 NEXT68K_LABEL_SECTOR * params->sectorsize + NEXT68K_LABEL_OFFSET); 112 if (rv == -1) { 113 warn("Reading `%s'", params->filesystem); 114 goto done; 115 } 116 if (rv != NEXT68K_LABEL_SIZE) { 117 warnx("Reading `%s': short read", params->filesystem); 118 goto done; 119 } 120 if (be32toh(next68klabel->cd_version) == NEXT68K_LABEL_CD_V3) { 121 checksum = &next68klabel->NEXT68K_LABEL_cd_v3_checksum; 122 } else { 123 checksum = &next68klabel->cd_checksum; 124 } 125 if (nextstep_checksum (next68klabel, checksum) != 126 be16toh(*checksum)) { 127 warn("Disklabel checksum invalid on `%s'", 128 params->filesystem); 129 goto done; 130 } 131 132 cd_secsize = be32toh(next68klabel->cd_secsize); 133 sec_netonb_mult = (cd_secsize / params->sectorsize); 134 135 /* 136 * Allocate a buffer, with space to round up the input file 137 * to the next block size boundary, and with space for the boot 138 * block. 139 */ 140 bootsize = roundup(params->s1stat.st_size, cd_secsize); 141 142 bootbuf = malloc(bootsize); 143 if (bootbuf == NULL) { 144 warn("Allocating %zu bytes", bootsize); 145 goto done; 146 } 147 memset(bootbuf, 0, bootsize); 148 149 /* 150 * Read the file into the buffer. 151 */ 152 rv = pread(params->s1fd, bootbuf, params->s1stat.st_size, 0); 153 if (rv == -1) { 154 warn("Reading `%s'", params->stage1); 155 goto done; 156 } else if (rv != params->s1stat.st_size) { 157 warnx("Reading `%s': short read", params->stage1); 158 goto done; 159 } 160 161 if (bootsize > be16toh(next68klabel->cd_front) * cd_secsize - 162 NEXT68K_LABEL_SIZE) { 163 warnx("Boot program is larger than front porch space"); 164 goto done; 165 } 166 167 fp = be16toh(next68klabel->cd_front); 168 b0 = be32toh(next68klabel->cd_boot_blkno[0]); 169 b1 = be32toh(next68klabel->cd_boot_blkno[1]); 170 171 if (b0 > fp) 172 b0 = fp; 173 if (b1 > fp) 174 b1 = fp; 175 if (((bootsize / cd_secsize) > b1 - b0) || 176 ((bootsize / cd_secsize) > fp - b1)) { 177 if (2 * bootsize > (fp * cd_secsize - NEXT68K_LABEL_SIZE)) 178 /* can only fit one copy */ 179 b0 = b1 = NEXT68K_LABEL_SIZE / cd_secsize; 180 else { 181 if (2 * bootsize > (fp * cd_secsize - 182 NEXT68K_LABEL_DEFAULTBOOT0_1 * 183 params->sectorsize)) 184 /* can fit two copies starting after label */ 185 b0 = NEXT68K_LABEL_SIZE / cd_secsize; 186 else 187 /* can fit two copies starting at default 1 */ 188 b0 = NEXT68K_LABEL_DEFAULTBOOT0_1 / 189 sec_netonb_mult; 190 /* try to fit 2nd copy at default 2 */ 191 b1 = NEXT68K_LABEL_DEFAULTBOOT0_2 / sec_netonb_mult; 192 if (fp < b1) 193 b1 = fp; 194 if (bootsize / cd_secsize > (fp - b1)) 195 /* fit 2nd copy before front porch */ 196 b1 = fp - bootsize / cd_secsize; 197 } 198 } 199 if (next68klabel->cd_boot_blkno[0] != (int32_t)htobe32(b0)) { 200 next68klabel->cd_boot_blkno[0] = htobe32(b0); 201 labelupdated = 1; 202 } 203 if (next68klabel->cd_boot_blkno[1] != (int32_t)htobe32(b1)) { 204 next68klabel->cd_boot_blkno[1] = htobe32(b1); 205 labelupdated = 1; 206 } 207 if (params->flags & IB_VERBOSE) 208 printf("Boot program locations%s: %d %d\n", 209 labelupdated ? " updated" : "", b0 * sec_netonb_mult, 210 b1 * sec_netonb_mult); 211 212 if (params->flags & IB_NOWRITE) { 213 retval = 1; 214 goto done; 215 } 216 217 /* 218 * Write the updated next68k disklabel 219 */ 220 if (labelupdated) { 221 if (params->flags & IB_VERBOSE) 222 printf ("Writing updated label\n"); 223 *checksum = htobe16(nextstep_checksum (next68klabel, 224 checksum)); 225 rv = pwrite(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE, 226 NEXT68K_LABEL_SECTOR * params->sectorsize + 227 NEXT68K_LABEL_OFFSET); 228 if (rv == -1) { 229 warn("Writing `%s'", params->filesystem); 230 goto done; 231 } 232 if (rv != NEXT68K_LABEL_SIZE) { 233 warnx("Writing `%s': short write", params->filesystem); 234 goto done; 235 } 236 } 237 238 b0 *= sec_netonb_mult; 239 b1 *= sec_netonb_mult; 240 241 /* 242 * Write boot program to locations b0 and b1 (if different). 243 */ 244 for (;;) { 245 if (params->flags & IB_VERBOSE) 246 printf ("Writing boot program at %d\n", b0); 247 rv = pwrite(params->fsfd, bootbuf, bootsize, 248 b0 * params->sectorsize); 249 if (rv == -1) { 250 warn("Writing `%s' at %d", params->filesystem, b0); 251 goto done; 252 } 253 if ((size_t)rv != bootsize) { 254 warnx("Writing `%s' at %d: short write", 255 params->filesystem, b0); 256 goto done; 257 } 258 if (b0 == b1) 259 break; 260 b0 = b1; 261 } 262 263 retval = 1; 264 265 done: 266 if (bootbuf) 267 free(bootbuf); 268 if (next68klabel) 269 free(next68klabel); 270 return retval; 271 } 272