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