1 /* $NetBSD: next68k.c,v 1.6 2009/04/05 11:55:39 lukem 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.6 2009/04/05 11:55:39 lukem 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 #define SECTOR_SIZE DEV_BSIZE 55 56 static uint16_t nextstep_checksum(const void *, const void *); 57 static int next68k_setboot(ib_params *); 58 59 struct ib_mach ib_mach_next68k = 60 { "next68k", next68k_setboot, no_clearboot, no_editboot, 0}; 61 62 static uint16_t 63 nextstep_checksum(const void *vbuf, const void *vlimit) 64 { 65 const uint16_t *buf = vbuf; 66 const uint16_t *limit = vlimit; 67 u_int sum = 0; 68 69 while (buf < limit) { 70 sum += be16toh(*buf++); 71 } 72 sum += (sum >> 16); 73 return (sum & 0xffff); 74 } 75 76 static int 77 next68k_setboot(ib_params *params) 78 { 79 int retval, labelupdated; 80 uint8_t *bootbuf; 81 size_t bootsize; 82 ssize_t rv; 83 uint32_t cd_secsize; 84 int sec_netonb_mult; 85 struct next68k_disklabel *next68klabel; 86 uint16_t *checksum; 87 uint32_t fp, b0, b1; 88 89 assert(params != NULL); 90 assert(params->fsfd != -1); 91 assert(params->filesystem != NULL); 92 assert(params->s1fd != -1); 93 assert(params->stage1 != NULL); 94 95 retval = 0; 96 labelupdated = 0; 97 bootbuf = NULL; 98 99 next68klabel = malloc(NEXT68K_LABEL_SIZE); 100 if (next68klabel == NULL) { 101 warn("Allocating %lu bytes", (unsigned long)NEXT68K_LABEL_SIZE); 102 goto done; 103 } 104 105 /* 106 * Read in the next68k disklabel 107 */ 108 rv = pread(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE, 109 NEXT68K_LABEL_SECTOR * SECTOR_SIZE + NEXT68K_LABEL_OFFSET); 110 if (rv == -1) { 111 warn("Reading `%s'", params->filesystem); 112 goto done; 113 } 114 if (rv != NEXT68K_LABEL_SIZE) { 115 warnx("Reading `%s': short read", params->filesystem); 116 goto done; 117 } 118 if (be32toh(next68klabel->cd_version) == NEXT68K_LABEL_CD_V3) { 119 checksum = &next68klabel->NEXT68K_LABEL_cd_v3_checksum; 120 } else { 121 checksum = &next68klabel->cd_checksum; 122 } 123 if (nextstep_checksum (next68klabel, checksum) != 124 be16toh(*checksum)) { 125 warn("Disklabel checksum invalid on `%s'", 126 params->filesystem); 127 goto done; 128 } 129 130 cd_secsize = be32toh(next68klabel->cd_secsize); 131 sec_netonb_mult = (cd_secsize / SECTOR_SIZE); 132 133 /* 134 * Allocate a buffer, with space to round up the input file 135 * to the next block size boundary, and with space for the boot 136 * block. 137 */ 138 bootsize = roundup(params->s1stat.st_size, cd_secsize); 139 140 bootbuf = malloc(bootsize); 141 if (bootbuf == NULL) { 142 warn("Allocating %zu bytes", bootsize); 143 goto done; 144 } 145 memset(bootbuf, 0, bootsize); 146 147 /* 148 * Read the file into the buffer. 149 */ 150 rv = pread(params->s1fd, bootbuf, params->s1stat.st_size, 0); 151 if (rv == -1) { 152 warn("Reading `%s'", params->stage1); 153 goto done; 154 } else if (rv != params->s1stat.st_size) { 155 warnx("Reading `%s': short read", params->stage1); 156 goto done; 157 } 158 159 if (bootsize > be16toh(next68klabel->cd_front) * cd_secsize - 160 NEXT68K_LABEL_SIZE) { 161 warnx("Boot program is larger than front porch space"); 162 goto done; 163 } 164 165 fp = be16toh(next68klabel->cd_front); 166 b0 = be32toh(next68klabel->cd_boot_blkno[0]); 167 b1 = be32toh(next68klabel->cd_boot_blkno[1]); 168 169 if (b0 > fp) 170 b0 = fp; 171 if (b1 > fp) 172 b1 = fp; 173 if (((bootsize / cd_secsize) > b1 - b0) || 174 ((bootsize / cd_secsize) > fp - b1)) { 175 if (2 * bootsize > (fp * cd_secsize - NEXT68K_LABEL_SIZE)) 176 /* can only fit one copy */ 177 b0 = b1 = NEXT68K_LABEL_SIZE / cd_secsize; 178 else { 179 if (2 * bootsize > (fp * cd_secsize - 180 NEXT68K_LABEL_DEFAULTBOOT0_1 * SECTOR_SIZE)) 181 /* can fit two copies starting after label */ 182 b0 = NEXT68K_LABEL_SIZE / cd_secsize; 183 else 184 /* can fit two copies starting at default 1 */ 185 b0 = NEXT68K_LABEL_DEFAULTBOOT0_1 / 186 sec_netonb_mult; 187 /* try to fit 2nd copy at default 2 */ 188 b1 = NEXT68K_LABEL_DEFAULTBOOT0_2 / sec_netonb_mult; 189 if (fp < b1) 190 b1 = fp; 191 if (bootsize / cd_secsize > (fp - b1)) 192 /* fit 2nd copy before front porch */ 193 b1 = fp - bootsize / cd_secsize; 194 } 195 } 196 if (next68klabel->cd_boot_blkno[0] != (int32_t)htobe32(b0)) { 197 next68klabel->cd_boot_blkno[0] = htobe32(b0); 198 labelupdated = 1; 199 } 200 if (next68klabel->cd_boot_blkno[1] != (int32_t)htobe32(b1)) { 201 next68klabel->cd_boot_blkno[1] = htobe32(b1); 202 labelupdated = 1; 203 } 204 if (params->flags & IB_VERBOSE) 205 printf("Boot programm locations%s: %d %d\n", 206 labelupdated ? " updated" : "", b0 * sec_netonb_mult, 207 b1 * sec_netonb_mult); 208 209 if (params->flags & IB_NOWRITE) { 210 retval = 1; 211 goto done; 212 } 213 214 /* 215 * Write the updated next68k disklabel 216 */ 217 if (labelupdated) { 218 if (params->flags & IB_VERBOSE) 219 printf ("Writing updated label\n"); 220 *checksum = htobe16(nextstep_checksum (next68klabel, 221 checksum)); 222 rv = pwrite(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE, 223 NEXT68K_LABEL_SECTOR * SECTOR_SIZE + NEXT68K_LABEL_OFFSET); 224 if (rv == -1) { 225 warn("Writing `%s'", params->filesystem); 226 goto done; 227 } 228 if (rv != NEXT68K_LABEL_SIZE) { 229 warnx("Writing `%s': short write", params->filesystem); 230 goto done; 231 } 232 } 233 234 b0 *= sec_netonb_mult; 235 b1 *= sec_netonb_mult; 236 237 /* 238 * Write boot program to locations b0 and b1 (if different). 239 */ 240 for (;;) { 241 if (params->flags & IB_VERBOSE) 242 printf ("Writing boot program at %d\n", b0); 243 rv = pwrite(params->fsfd, bootbuf, bootsize, b0 * SECTOR_SIZE); 244 if (rv == -1) { 245 warn("Writing `%s' at %d", params->filesystem, b0); 246 goto done; 247 } 248 if ((size_t)rv != bootsize) { 249 warnx("Writing `%s' at %d: short write", 250 params->filesystem, b0); 251 goto done; 252 } 253 if (b0 == b1) 254 break; 255 b0 = b1; 256 } 257 258 retval = 1; 259 260 done: 261 if (bootbuf) 262 free(bootbuf); 263 if (next68klabel) 264 free(next68klabel); 265 return retval; 266 } 267