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