xref: /netbsd-src/usr.sbin/installboot/arch/next68k.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
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