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