1 /* $NetBSD: next68k.c,v 1.3 2004/06/20 22:20:17 jmc 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.3 2004/06/20 22:20:17 jmc 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 65 static uint16_t 66 nextstep_checksum(const void *vbuf, const void *vlimit) 67 { 68 const uint16_t *buf = vbuf; 69 const uint16_t *limit = vlimit; 70 u_int sum = 0; 71 72 while (buf < limit) { 73 sum += be16toh(*buf++); 74 } 75 sum += (sum >> 16); 76 return (sum & 0xffff); 77 } 78 79 int 80 next68k_setboot(ib_params *params) 81 { 82 int retval, labelupdated; 83 uint8_t *bootbuf; 84 u_int bootsize; 85 ssize_t rv; 86 uint32_t cd_secsize; 87 int sec_netonb_mult; 88 struct next68k_disklabel *next68klabel; 89 uint16_t *checksum; 90 uint32_t fp, b0, b1; 91 92 assert(params != NULL); 93 assert(params->fsfd != -1); 94 assert(params->filesystem != NULL); 95 assert(params->s1fd != -1); 96 assert(params->stage1 != NULL); 97 98 retval = 0; 99 labelupdated = 0; 100 bootbuf = NULL; 101 102 next68klabel = malloc(NEXT68K_LABEL_SIZE); 103 if (next68klabel == NULL) { 104 warn("Allocating %lu bytes", (unsigned long)NEXT68K_LABEL_SIZE); 105 goto done; 106 } 107 108 /* 109 * Read in the next68k disklabel 110 */ 111 rv = pread(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE, 112 NEXT68K_LABEL_SECTOR * SECTOR_SIZE + NEXT68K_LABEL_OFFSET); 113 if (rv == -1) { 114 warn("Reading `%s'", params->filesystem); 115 goto done; 116 } 117 if (rv != NEXT68K_LABEL_SIZE) { 118 warnx("Reading `%s': short read", params->filesystem); 119 goto done; 120 } 121 if (be32toh(next68klabel->cd_version) == NEXT68K_LABEL_CD_V3) { 122 checksum = &next68klabel->NEXT68K_LABEL_cd_v3_checksum; 123 } else { 124 checksum = &next68klabel->cd_checksum; 125 } 126 if (nextstep_checksum (next68klabel, checksum) != 127 be16toh(*checksum)) { 128 warn("Disklabel checksum invalid on `%s'", 129 params->filesystem); 130 goto done; 131 } 132 133 cd_secsize = be32toh(next68klabel->cd_secsize); 134 sec_netonb_mult = (cd_secsize / SECTOR_SIZE); 135 136 /* 137 * Allocate a buffer, with space to round up the input file 138 * to the next block size boundary, and with space for the boot 139 * block. 140 */ 141 bootsize = roundup(params->s1stat.st_size, cd_secsize); 142 143 bootbuf = malloc(bootsize); 144 if (bootbuf == NULL) { 145 warn("Allocating %lu bytes", (unsigned long)bootsize); 146 goto done; 147 } 148 memset(bootbuf, 0, bootsize); 149 150 /* 151 * Read the file into the buffer. 152 */ 153 rv = pread(params->s1fd, bootbuf, params->s1stat.st_size, 0); 154 if (rv == -1) { 155 warn("Reading `%s'", params->stage1); 156 goto done; 157 } else if (rv != params->s1stat.st_size) { 158 warnx("Reading `%s': short read", params->stage1); 159 goto done; 160 } 161 162 if (bootsize > be16toh(next68klabel->cd_front) * cd_secsize - 163 NEXT68K_LABEL_SIZE) { 164 warnx("Boot program is larger than front porch space"); 165 goto done; 166 } 167 168 fp = be16toh(next68klabel->cd_front); 169 b0 = be32toh(next68klabel->cd_boot_blkno[0]); 170 b1 = be32toh(next68klabel->cd_boot_blkno[1]); 171 172 if (b0 > fp) 173 b0 = fp; 174 if (b1 > fp) 175 b1 = fp; 176 if (((bootsize / cd_secsize) > b1 - b0) || 177 ((bootsize / cd_secsize) > fp - b1)) { 178 if (2 * bootsize > (fp * cd_secsize - NEXT68K_LABEL_SIZE)) 179 /* can only fit one copy */ 180 b0 = b1 = NEXT68K_LABEL_SIZE / cd_secsize; 181 else { 182 if (2 * bootsize > (fp * cd_secsize - 183 NEXT68K_LABEL_DEFAULTBOOT0_1 * SECTOR_SIZE)) 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] != htobe32(b0)) { 200 next68klabel->cd_boot_blkno[0] = htobe32(b0); 201 labelupdated = 1; 202 } 203 if (next68klabel->cd_boot_blkno[1] != htobe32(b1)) { 204 next68klabel->cd_boot_blkno[1] = htobe32(b1); 205 labelupdated = 1; 206 } 207 if (params->flags & IB_VERBOSE) 208 printf("Boot programm 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 * SECTOR_SIZE + NEXT68K_LABEL_OFFSET); 227 if (rv == -1) { 228 warn("Writing `%s'", params->filesystem); 229 goto done; 230 } 231 if (rv != NEXT68K_LABEL_SIZE) { 232 warnx("Writing `%s': short write", params->filesystem); 233 goto done; 234 } 235 } 236 237 b0 *= sec_netonb_mult; 238 b1 *= sec_netonb_mult; 239 240 /* 241 * Write boot program to locations b0 and b1 (if different). 242 */ 243 for (;;) { 244 if (params->flags & IB_VERBOSE) 245 printf ("Writing boot program at %d\n", b0); 246 rv = pwrite(params->fsfd, bootbuf, bootsize, b0 * SECTOR_SIZE); 247 if (rv == -1) { 248 warn("Writing `%s' at %d", params->filesystem, b0); 249 goto done; 250 } 251 if (rv != bootsize) { 252 warnx("Writing `%s' at %d: short write", 253 params->filesystem, b0); 254 goto done; 255 } 256 if (b0 == b1) 257 break; 258 b0 = b1; 259 } 260 261 retval = 1; 262 263 done: 264 if (bootbuf) 265 free(bootbuf); 266 if (next68klabel) 267 free(next68klabel); 268 return retval; 269 } 270